├── .gitignore
├── LICENSE
├── README.md
├── archive
└── dive-into-kubernetes-informer
│ ├── 1-list-watcher
│ ├── clientset.go
│ └── main.go
│ ├── 10-sloth-controller
│ └── main.go
│ ├── 11-crd-informer
│ ├── api
│ │ └── stable.wbsnail.com
│ │ │ └── v1
│ │ │ ├── doc.go
│ │ │ ├── register.go
│ │ │ ├── types.go
│ │ │ └── zz_generated.deepcopy.go
│ ├── boilerplate.go.txt
│ ├── client
│ │ ├── clientset
│ │ │ └── versioned
│ │ │ │ ├── clientset.go
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake
│ │ │ │ ├── clientset_generated.go
│ │ │ │ ├── doc.go
│ │ │ │ └── register.go
│ │ │ │ ├── scheme
│ │ │ │ ├── doc.go
│ │ │ │ └── register.go
│ │ │ │ └── typed
│ │ │ │ └── stable.wbsnail.com
│ │ │ │ └── v1
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake_rabbit.go
│ │ │ │ └── fake_stable.wbsnail.com_client.go
│ │ │ │ ├── generated_expansion.go
│ │ │ │ ├── rabbit.go
│ │ │ │ └── stable.wbsnail.com_client.go
│ │ ├── informers
│ │ │ └── externalversions
│ │ │ │ ├── factory.go
│ │ │ │ ├── generic.go
│ │ │ │ ├── internalinterfaces
│ │ │ │ └── factory_interfaces.go
│ │ │ │ └── stable.wbsnail.com
│ │ │ │ ├── interface.go
│ │ │ │ └── v1
│ │ │ │ ├── interface.go
│ │ │ │ └── rabbit.go
│ │ └── listers
│ │ │ └── stable.wbsnail.com
│ │ │ └── v1
│ │ │ ├── expansion_generated.go
│ │ │ └── rabbit.go
│ ├── crd.yaml
│ ├── custom-resource.yaml
│ ├── generate-groups.sh
│ └── main.go
│ ├── 12-dynamic-informer
│ └── main.go
│ ├── 2-reflector
│ ├── clientset.go
│ ├── lw.go
│ └── main.go
│ ├── 3-controller
│ ├── clientset.go
│ ├── lw.go
│ ├── main.go
│ └── store.go
│ ├── 4-informer
│ ├── clientset.go
│ ├── lw.go
│ └── main.go
│ ├── 5-shared-informer
│ ├── clientset.go
│ ├── lw.go
│ └── main.go
│ ├── 6-indexer
│ ├── clientset.go
│ ├── lw.go
│ └── main.go
│ ├── 7-indexer-informer
│ ├── clientset.go
│ ├── lw.go
│ ├── main.go
│ └── probe-server.go
│ ├── 8-shared-index-informer
│ ├── clientset.go
│ ├── lw.go
│ ├── main.go
│ └── probe-server.go
│ ├── 9-shared-informer-factory
│ ├── clientset.go
│ └── main.go
│ ├── go.mod
│ ├── go.sum
│ ├── informer.drawio
│ └── probe
│ └── main.go
├── go.mod
├── go.sum
└── lab
├── csrf-attack
├── attacker-website
│ └── main.go
├── go.mod
├── go.sum
├── server-protected
│ └── main.go
└── server-volunable
│ └── main.go
├── shadow-string
├── go.mod
├── go.sum
└── main.go
├── unix-socket-broadcast
├── client
│ └── main.go
├── go.mod
├── go.sum
└── server
│ └── main.go
├── unix-socket-echo
├── client
│ └── main.go
├── go.mod
├── go.sum
└── server
│ └── main.go
├── upgrade-plan
└── main.go
└── xss-attack
├── go.mod
├── go.sum
└── main.go
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.toptal.com/developers/gitignore/api/go,node,macos,linux,vscode,windows,jetbrains
3 | # Edit at https://www.toptal.com/developers/gitignore?templates=go,node,macos,linux,vscode,windows,jetbrains
4 |
5 | ### Go ###
6 | # Binaries for programs and plugins
7 | *.exe
8 | *.exe~
9 | *.dll
10 | *.so
11 | *.dylib
12 |
13 | # Test binary, built with `go test -c`
14 | *.test
15 |
16 | # Output of the go coverage tool, specifically when used with LiteIDE
17 | *.out
18 |
19 | # Dependency directories (remove the comment below to include it)
20 | # vendor/
21 |
22 | ### Go Patch ###
23 | /vendor/
24 | /Godeps/
25 |
26 | ### JetBrains ###
27 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
28 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
29 |
30 | # User-specific stuff
31 | .idea/**/workspace.xml
32 | .idea/**/tasks.xml
33 | .idea/**/usage.statistics.xml
34 | .idea/**/dictionaries
35 | .idea/**/shelf
36 |
37 | # Generated files
38 | .idea/**/contentModel.xml
39 |
40 | # Sensitive or high-churn files
41 | .idea/**/dataSources/
42 | .idea/**/dataSources.ids
43 | .idea/**/dataSources.local.xml
44 | .idea/**/sqlDataSources.xml
45 | .idea/**/dynamic.xml
46 | .idea/**/uiDesigner.xml
47 | .idea/**/dbnavigator.xml
48 |
49 | # Gradle
50 | .idea/**/gradle.xml
51 | .idea/**/libraries
52 |
53 | # Gradle and Maven with auto-import
54 | # When using Gradle or Maven with auto-import, you should exclude module files,
55 | # since they will be recreated, and may cause churn. Uncomment if using
56 | # auto-import.
57 | # .idea/artifacts
58 | # .idea/compiler.xml
59 | # .idea/jarRepositories.xml
60 | # .idea/modules.xml
61 | # .idea/*.iml
62 | # .idea/modules
63 | # *.iml
64 | # *.ipr
65 |
66 | # CMake
67 | cmake-build-*/
68 |
69 | # Mongo Explorer plugin
70 | .idea/**/mongoSettings.xml
71 |
72 | # File-based project format
73 | *.iws
74 |
75 | # IntelliJ
76 | out/
77 |
78 | # mpeltonen/sbt-idea plugin
79 | .idea_modules/
80 |
81 | # JIRA plugin
82 | atlassian-ide-plugin.xml
83 |
84 | # Cursive Clojure plugin
85 | .idea/replstate.xml
86 |
87 | # Crashlytics plugin (for Android Studio and IntelliJ)
88 | com_crashlytics_export_strings.xml
89 | crashlytics.properties
90 | crashlytics-build.properties
91 | fabric.properties
92 |
93 | # Editor-based Rest Client
94 | .idea/httpRequests
95 |
96 | # Android studio 3.1+ serialized cache file
97 | .idea/caches/build_file_checksums.ser
98 |
99 | ### JetBrains Patch ###
100 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
101 |
102 | # *.iml
103 | # modules.xml
104 | # .idea/misc.xml
105 | # *.ipr
106 |
107 | # Sonarlint plugin
108 | # https://plugins.jetbrains.com/plugin/7973-sonarlint
109 | .idea/**/sonarlint/
110 |
111 | # SonarQube Plugin
112 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
113 | .idea/**/sonarIssues.xml
114 |
115 | # Markdown Navigator plugin
116 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
117 | .idea/**/markdown-navigator.xml
118 | .idea/**/markdown-navigator-enh.xml
119 | .idea/**/markdown-navigator/
120 |
121 | # Cache file creation bug
122 | # See https://youtrack.jetbrains.com/issue/JBR-2257
123 | .idea/$CACHE_FILE$
124 |
125 | # CodeStream plugin
126 | # https://plugins.jetbrains.com/plugin/12206-codestream
127 | .idea/codestream.xml
128 |
129 | ### Linux ###
130 | *~
131 |
132 | # temporary files which can be created if a process still has a handle open of a deleted file
133 | .fuse_hidden*
134 |
135 | # KDE directory preferences
136 | .directory
137 |
138 | # Linux trash folder which might appear on any partition or disk
139 | .Trash-*
140 |
141 | # .nfs files are created when an open file is removed but is still being accessed
142 | .nfs*
143 |
144 | ### macOS ###
145 | # General
146 | .DS_Store
147 | .AppleDouble
148 | .LSOverride
149 |
150 | # Icon must end with two \r
151 | Icon
152 |
153 |
154 | # Thumbnails
155 | ._*
156 |
157 | # Files that might appear in the root of a volume
158 | .DocumentRevisions-V100
159 | .fseventsd
160 | .Spotlight-V100
161 | .TemporaryItems
162 | .Trashes
163 | .VolumeIcon.icns
164 | .com.apple.timemachine.donotpresent
165 |
166 | # Directories potentially created on remote AFP share
167 | .AppleDB
168 | .AppleDesktop
169 | Network Trash Folder
170 | Temporary Items
171 | .apdisk
172 |
173 | ### Node ###
174 | # Logs
175 | logs
176 | *.log
177 | npm-debug.log*
178 | yarn-debug.log*
179 | yarn-error.log*
180 | lerna-debug.log*
181 |
182 | # Diagnostic reports (https://nodejs.org/api/report.html)
183 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
184 |
185 | # Runtime data
186 | pids
187 | *.pid
188 | *.seed
189 | *.pid.lock
190 |
191 | # Directory for instrumented libs generated by jscoverage/JSCover
192 | lib-cov
193 |
194 | # Coverage directory used by tools like istanbul
195 | coverage
196 | *.lcov
197 |
198 | # nyc test coverage
199 | .nyc_output
200 |
201 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
202 | .grunt
203 |
204 | # Bower dependency directory (https://bower.io/)
205 | bower_components
206 |
207 | # node-waf configuration
208 | .lock-wscript
209 |
210 | # Compiled binary addons (https://nodejs.org/api/addons.html)
211 | build/Release
212 |
213 | # Dependency directories
214 | node_modules/
215 | jspm_packages/
216 |
217 | # TypeScript v1 declaration files
218 | typings/
219 |
220 | # TypeScript cache
221 | *.tsbuildinfo
222 |
223 | # Optional npm cache directory
224 | .npm
225 |
226 | # Optional eslint cache
227 | .eslintcache
228 |
229 | # Optional stylelint cache
230 | .stylelintcache
231 |
232 | # Microbundle cache
233 | .rpt2_cache/
234 | .rts2_cache_cjs/
235 | .rts2_cache_es/
236 | .rts2_cache_umd/
237 |
238 | # Optional REPL history
239 | .node_repl_history
240 |
241 | # Output of 'npm pack'
242 | *.tgz
243 |
244 | # Yarn Integrity file
245 | .yarn-integrity
246 |
247 | # dotenv environment variables file
248 | .env
249 | .env.test
250 | .env*.local
251 |
252 | # parcel-bundler cache (https://parceljs.org/)
253 | .cache
254 | .parcel-cache
255 |
256 | # Next.js build output
257 | .next
258 |
259 | # Nuxt.js build / generate output
260 | .nuxt
261 | dist
262 |
263 | # Storybook build outputs
264 | .out
265 | .storybook-out
266 | storybook-static
267 |
268 | # rollup.js default build output
269 | dist/
270 |
271 | # Gatsby files
272 | .cache/
273 | # Comment in the public line in if your project uses Gatsby and not Next.js
274 | # https://nextjs.org/blog/next-9-1#public-directory-support
275 | # public
276 |
277 | # vuepress build output
278 | .vuepress/dist
279 |
280 | # Serverless directories
281 | .serverless/
282 |
283 | # FuseBox cache
284 | .fusebox/
285 |
286 | # DynamoDB Local files
287 | .dynamodb/
288 |
289 | # TernJS port file
290 | .tern-port
291 |
292 | # Stores VSCode versions used for testing VSCode extensions
293 | .vscode-test
294 |
295 | # Temporary folders
296 | tmp/
297 | temp/
298 |
299 | ### vscode ###
300 | .vscode/*
301 | !.vscode/settings.json
302 | !.vscode/tasks.json
303 | !.vscode/launch.json
304 | !.vscode/extensions.json
305 | *.code-workspace
306 |
307 | ### Windows ###
308 | # Windows thumbnail cache files
309 | Thumbs.db
310 | Thumbs.db:encryptable
311 | ehthumbs.db
312 | ehthumbs_vista.db
313 |
314 | # Dump file
315 | *.stackdump
316 |
317 | # Folder config file
318 | [Dd]esktop.ini
319 |
320 | # Recycle Bin used on file shares
321 | $RECYCLE.BIN/
322 |
323 | # Windows Installer files
324 | *.cab
325 | *.msi
326 | *.msix
327 | *.msm
328 | *.msp
329 |
330 | # Windows shortcuts
331 | *.lnk
332 |
333 | # End of https://www.toptal.com/developers/gitignore/api/go,node,macos,linux,vscode,windows,jetbrains
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # articles
2 | Articles written by me.
3 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/1-list-watcher/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/1-list-watcher/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/spongeprojects/magicconch"
6 | corev1 "k8s.io/api/core/v1"
7 | "k8s.io/apimachinery/pkg/api/meta"
8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | "k8s.io/apimachinery/pkg/fields"
10 | "k8s.io/client-go/tools/cache"
11 | "os"
12 | "os/signal"
13 | )
14 |
15 | // newConfigMapsListerWatcher 用于创建 tmp namespace 下 configmaps 资源的 ListerWatcher 实例
16 | func newConfigMapsListerWatcher() cache.ListerWatcher {
17 | clientset := mustClientset() // 前面有说明
18 | client := clientset.CoreV1().RESTClient() // 客户端,请求器
19 | resource := "configmaps" // GET 请求参数之一
20 | namespace := "tmp" // GET 请求参数之一
21 | selector := fields.Everything() // GET 请求参数之一
22 | lw := cache.NewListWatchFromClient(client, resource, namespace, selector)
23 | return lw
24 | }
25 |
26 | func main() {
27 | fmt.Println("----- 1-list-watcher -----")
28 |
29 | lw := newConfigMapsListerWatcher()
30 |
31 | // list 的类型为 runtime.Object, 需要经过反射或类型转换才能使用,
32 | // 传入的 ListOptions 中的 FieldSelector 始终会被替换为前面的 selector
33 | list, err := lw.List(metav1.ListOptions{})
34 | magicconch.Must(err)
35 |
36 | // meta 包封装了一些处理 runtime.Object 对象的方法,屏蔽了反射和类型转换的过程,
37 | // 提取出的 items 类型为 []runtime.Object
38 | items, err := meta.ExtractList(list)
39 | magicconch.Must(err)
40 |
41 | fmt.Println("Initial list:")
42 |
43 | for _, item := range items {
44 | configMap, ok := item.(*corev1.ConfigMap)
45 | if !ok {
46 | return
47 | }
48 | fmt.Println(configMap.Name)
49 |
50 | // 如果只关注 meta 信息,也可以不进行类型转换,而是使用 meta.Accessor 方法
51 | // accessor, err := meta.Accessor(item)
52 | // magicconch.Must(err)
53 | // fmt.Println(accessor.GetName())
54 | }
55 |
56 | listMetaInterface, err := meta.ListAccessor(list)
57 | magicconch.Must(err)
58 |
59 | // resourceVersion 在同步过程中非常重要,看下面它在 Watch 接口中的使用
60 | resourceVersion := listMetaInterface.GetResourceVersion()
61 |
62 | // w 的类型为 watch.Interface,提供 ResultChan 方法读取事件,
63 | // 和 List 一样,传入的 ListOptions 中的 FieldSelector 始终会被替换为前面的 selector,
64 | // ResourceVersion 是 Watch 时非常重要的参数,
65 | // 它代表一次客户端与服务器进行交互时对应的资源版本,
66 | // 结合另一个参数 ResourceVersionMatch,表示本次请求对 ResourceVersion 的筛选,
67 | // 比如以下请求表示:获取版本新于 resourceVersion 的事件。
68 | // 在考虑连接中断和定期重新同步 (resync) 的情况下,
69 | // 对 ResourceVersion 的管理就变得更为复杂,我们先不考虑这些情况。
70 | w, err := lw.Watch(metav1.ListOptions{
71 | ResourceVersion: resourceVersion,
72 | })
73 | magicconch.Must(err)
74 |
75 | stopCh := make(chan os.Signal)
76 | signal.Notify(stopCh, os.Interrupt)
77 |
78 | fmt.Println("Start watching...")
79 |
80 | loop:
81 | for {
82 | select {
83 | case <-stopCh:
84 | fmt.Println("Interrupted")
85 | break loop
86 | case event, ok := <-w.ResultChan():
87 | if !ok {
88 | fmt.Println("Broken channel")
89 | break loop
90 | }
91 | configMap, ok := event.Object.(*corev1.ConfigMap)
92 | if !ok {
93 | return
94 | }
95 | fmt.Printf("%s: %s\n", event.Type, configMap.Name)
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/10-sloth-controller/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "github.com/spongeprojects/magicconch"
7 | "k8s.io/apimachinery/pkg/util/rand"
8 | "k8s.io/apimachinery/pkg/util/runtime"
9 | "k8s.io/apimachinery/pkg/util/wait"
10 | "k8s.io/client-go/informers"
11 | "k8s.io/client-go/kubernetes"
12 | listerscorev1 "k8s.io/client-go/listers/core/v1"
13 | "k8s.io/client-go/tools/cache"
14 | "k8s.io/client-go/tools/clientcmd"
15 | "k8s.io/client-go/util/workqueue"
16 | "k8s.io/klog/v2"
17 | "os"
18 | "os/signal"
19 | "sync"
20 | "time"
21 | )
22 |
23 | // SlothController 树懒控制器!
24 | type SlothController struct {
25 | factory informers.SharedInformerFactory
26 | configMapLister listerscorev1.ConfigMapLister
27 | configMapInformer cache.SharedIndexInformer
28 | queue workqueue.RateLimitingInterface
29 | processingItems *sync.WaitGroup
30 |
31 | // maxRetries 树懒们需要重试多少次才会放弃
32 | maxRetries int
33 | // chanceOfFailure 树懒们处理任务有多少概率失败(百分比)
34 | chanceOfFailure int
35 | // nap 树懒睡一觉要多久
36 | nap time.Duration
37 | }
38 |
39 | func NewController(
40 | factory informers.SharedInformerFactory,
41 | queue workqueue.RateLimitingInterface,
42 | chanceOfFailure int,
43 | nap time.Duration,
44 | ) *SlothController {
45 | configMapLister := factory.Core().V1().ConfigMaps().Lister()
46 | configMapInformer := factory.Core().V1().ConfigMaps().Informer()
47 | configMapInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
48 | UpdateFunc: func(old interface{}, new interface{}) {
49 | key, err := cache.MetaNamespaceKeyFunc(new)
50 | if err == nil {
51 | // 只简单地把 key 放到队列中
52 | klog.Infof("[%s] received", key)
53 | queue.Add(key)
54 | }
55 | },
56 | })
57 |
58 | return &SlothController{
59 | factory: factory,
60 | configMapLister: configMapLister,
61 | configMapInformer: configMapInformer,
62 | queue: queue,
63 | maxRetries: 3,
64 | chanceOfFailure: chanceOfFailure,
65 | nap: nap,
66 | processingItems: &sync.WaitGroup{},
67 | }
68 | }
69 |
70 | // Run 开始运行控制器直到出错或 stopCh 关闭
71 | func (c *SlothController) Run(sloths int, stopCh chan struct{}) error {
72 | // runtime.HandleCrash 是 Kubernetes 官方提供的 panic recover 方法,
73 | // 提供一个 panic recover 的统一入口,
74 | // 默认只是记录日志,该 panic 还是 panic。
75 | defer runtime.HandleCrash()
76 | // 退出前关闭队列让树懒们不要再接手新任务
77 | defer c.queue.ShutDown()
78 |
79 | klog.Info("SlothController starting...")
80 |
81 | go c.factory.Start(stopCh)
82 |
83 | // 等待首次同步完成
84 | for _, ok := range c.factory.WaitForCacheSync(stopCh) {
85 | if !ok {
86 | return fmt.Errorf("timed out waiting for caches to sync")
87 | }
88 | }
89 |
90 | for i := 0; i < sloths; i++ {
91 | go wait.Until(c.runWorker, time.Second, stopCh)
92 | }
93 |
94 | // 等待 stopCh 关闭
95 | <-stopCh
96 |
97 | // 等待正在执行中的任务完成
98 | klog.Info("waiting for processing items to finish...")
99 | c.processingItems.Wait()
100 |
101 | return nil
102 | }
103 |
104 | func (c *SlothController) runWorker() {
105 | for c.processNextItem() {
106 | }
107 | }
108 |
109 | // processNextItem 用于等待和处理队列中的新任务
110 | func (c *SlothController) processNextItem() bool {
111 | // 阻塞住,等待新任务中...
112 | key, shutdown := c.queue.Get()
113 | if shutdown {
114 | return false // 队列已进入退出状态,不要继续处理
115 | }
116 |
117 | c.processingItems.Add(1)
118 |
119 | // 任务完成后,无论成功与否,都记得标记完成,因为尽管有多只树懒,
120 | // 但对相同 key 的多个任务是不会并行处理的,
121 | // 如果相同 key 有多个事件,不要阻塞处理。
122 | defer c.queue.Done(key)
123 |
124 | result := c.processItem(key)
125 | c.handleErr(key, result)
126 |
127 | c.processingItems.Done()
128 |
129 | return true
130 | }
131 |
132 | // processItem 用于同步处理一个任务
133 | func (c *SlothController) processItem(key interface{}) error {
134 | // 处理任务很慢,因为树懒很懒
135 | time.Sleep(c.nap)
136 |
137 | if rand.Intn(100) < c.chanceOfFailure {
138 | // 睡过头啦!
139 | return fmt.Errorf("zzz... ")
140 | }
141 |
142 | klog.Infof("[%s] processed.", key)
143 | return nil
144 | }
145 |
146 | // handleErr 用于检查任务处理结果,在必要的时候重试
147 | func (c *SlothController) handleErr(key interface{}, result error) {
148 | if result == nil {
149 | // 每次执行成功后清空重试记录。
150 | c.queue.Forget(key)
151 | return
152 | }
153 |
154 | if c.queue.NumRequeues(key) < c.maxRetries {
155 | klog.Warningf("error processing %s: %v", key, result)
156 | // 执行失败,重试
157 | c.queue.AddRateLimited(key)
158 | return
159 | }
160 |
161 | // 重试次数过多,日志记录错误,同时也别忘了清空重试记录
162 | c.queue.Forget(key)
163 | // runtime.HandleError 是 Kubernetes 官方提供的错误响应方法,
164 | // 提供一个错误响应的统一入口。
165 | runtime.HandleError(fmt.Errorf("max retries exceeded, "+
166 | "dropping item %s out of the queue: %v", key, result))
167 | }
168 |
169 | func main() {
170 | fmt.Println("----- 10-sloth-controller -----")
171 |
172 | var sloths int
173 | var chanceOfFailure int
174 | var napInSecond int
175 | flag.IntVar(&sloths, "sloths", 1,
176 | "number of sloths")
177 | flag.IntVar(&chanceOfFailure, "chance-of-failure", 0,
178 | "chance of failure in percentage")
179 | flag.IntVar(&napInSecond, "nap", 0,
180 | "how long should the sloth nap (in seconds)")
181 | flag.Parse()
182 |
183 | kubeconfig := os.Getenv("KUBECONFIG")
184 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
185 | magicconch.Must(err)
186 |
187 | clientset, err := kubernetes.NewForConfig(config)
188 | magicconch.Must(err)
189 |
190 | // 创建 SharedInformerFactory
191 | defaultResyncPeriod := time.Hour * 12
192 | informerFactory := informers.NewSharedInformerFactoryWithOptions(
193 | clientset, defaultResyncPeriod, informers.WithNamespace("tmp"))
194 |
195 | // 使用默认配置创建 RateLimitingQueue,这种队列支持重试,同时会记录重试次数
196 | rateLimiter := workqueue.DefaultControllerRateLimiter()
197 | queue := workqueue.NewRateLimitingQueue(rateLimiter)
198 |
199 | controller := NewController(informerFactory, queue, chanceOfFailure,
200 | time.Duration(napInSecond)*time.Second)
201 |
202 | stopCh := make(chan struct{})
203 |
204 | // 响应中断信号 (Ctrl+C)
205 | interrupted := make(chan os.Signal)
206 | signal.Notify(interrupted, os.Interrupt)
207 |
208 | go func() {
209 | <-interrupted // 第 1 次收到中断信号时关闭 stopCh
210 | close(stopCh)
211 | <-interrupted // 第 2 次收到中断信号时直接退出
212 | os.Exit(1)
213 | }()
214 |
215 | if err := controller.Run(sloths, stopCh); err != nil {
216 | klog.Errorf("SlothController exit with error: %s", err)
217 | } else {
218 | klog.Info("SlothController exit")
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1/doc.go:
--------------------------------------------------------------------------------
1 | // +k8s:deepcopy-gen=package
2 |
3 | package v1
4 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1/register.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5 | "k8s.io/apimachinery/pkg/runtime"
6 | "k8s.io/apimachinery/pkg/runtime/schema"
7 | )
8 |
9 | // SchemeGroupVersion is group version used to register these objects
10 | var SchemeGroupVersion = schema.GroupVersion{Group: "stable.wbsnail.com", Version: "v1"}
11 |
12 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind
13 | func Kind(kind string) schema.GroupKind {
14 | return SchemeGroupVersion.WithKind(kind).GroupKind()
15 | }
16 |
17 | // Resource takes an unqualified resource and returns a Group qualified GroupResource
18 | func Resource(resource string) schema.GroupResource {
19 | return SchemeGroupVersion.WithResource(resource).GroupResource()
20 | }
21 |
22 | var (
23 | // SchemeBuilder initializes a scheme builder
24 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
25 | // AddToScheme is a global function that registers this API group & version to a scheme
26 | AddToScheme = SchemeBuilder.AddToScheme
27 | )
28 |
29 | // Adds the list of known types to Scheme.
30 | func addKnownTypes(scheme *runtime.Scheme) error {
31 | scheme.AddKnownTypes(SchemeGroupVersion,
32 | &Rabbit{},
33 | &RabbitList{},
34 | )
35 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
36 | return nil
37 | }
38 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1/types.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4 |
5 | // +genclient
6 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
7 |
8 | // Rabbit is a top-level type
9 | type Rabbit struct {
10 | metav1.TypeMeta `json:",inline"`
11 | // +optional
12 | metav1.ObjectMeta `json:"metadata,omitempty"`
13 |
14 | // This is where you can define
15 | // your own custom spec
16 | Spec RabbitSpec `json:"spec,omitempty"`
17 | }
18 |
19 | type RabbitSpec struct {
20 | Color string `json:"color,omitempty"`
21 | }
22 |
23 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
24 |
25 | // RabbitList no client needed for list as it's been created in above
26 | type RabbitList struct {
27 | metav1.TypeMeta `json:",inline"`
28 | // +optional
29 | metav1.ListMeta `son:"metadata,omitempty"`
30 |
31 | Items []Rabbit `json:"items"`
32 | }
33 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1/zz_generated.deepcopy.go:
--------------------------------------------------------------------------------
1 | // +build !ignore_autogenerated
2 |
3 | /*
4 | Copyright wbsnail.com.
5 |
6 | Licensed under the Apache License, Version 2.0 (the "License");
7 | you may not use this file except in compliance with the License.
8 | You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing, software
13 | distributed under the License is distributed on an "AS IS" BASIS,
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | See the License for the specific language governing permissions and
16 | limitations under the License.
17 | */
18 |
19 | // Code generated by deepcopy-gen. DO NOT EDIT.
20 |
21 | package v1
22 |
23 | import (
24 | runtime "k8s.io/apimachinery/pkg/runtime"
25 | )
26 |
27 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
28 | func (in *Rabbit) DeepCopyInto(out *Rabbit) {
29 | *out = *in
30 | out.TypeMeta = in.TypeMeta
31 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
32 | out.Spec = in.Spec
33 | return
34 | }
35 |
36 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rabbit.
37 | func (in *Rabbit) DeepCopy() *Rabbit {
38 | if in == nil {
39 | return nil
40 | }
41 | out := new(Rabbit)
42 | in.DeepCopyInto(out)
43 | return out
44 | }
45 |
46 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
47 | func (in *Rabbit) DeepCopyObject() runtime.Object {
48 | if c := in.DeepCopy(); c != nil {
49 | return c
50 | }
51 | return nil
52 | }
53 |
54 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
55 | func (in *RabbitList) DeepCopyInto(out *RabbitList) {
56 | *out = *in
57 | out.TypeMeta = in.TypeMeta
58 | in.ListMeta.DeepCopyInto(&out.ListMeta)
59 | if in.Items != nil {
60 | in, out := &in.Items, &out.Items
61 | *out = make([]Rabbit, len(*in))
62 | for i := range *in {
63 | (*in)[i].DeepCopyInto(&(*out)[i])
64 | }
65 | }
66 | return
67 | }
68 |
69 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitList.
70 | func (in *RabbitList) DeepCopy() *RabbitList {
71 | if in == nil {
72 | return nil
73 | }
74 | out := new(RabbitList)
75 | in.DeepCopyInto(out)
76 | return out
77 | }
78 |
79 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
80 | func (in *RabbitList) DeepCopyObject() runtime.Object {
81 | if c := in.DeepCopy(); c != nil {
82 | return c
83 | }
84 | return nil
85 | }
86 |
87 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
88 | func (in *RabbitSpec) DeepCopyInto(out *RabbitSpec) {
89 | *out = *in
90 | return
91 | }
92 |
93 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitSpec.
94 | func (in *RabbitSpec) DeepCopy() *RabbitSpec {
95 | if in == nil {
96 | return nil
97 | }
98 | out := new(RabbitSpec)
99 | in.DeepCopyInto(out)
100 | return out
101 | }
102 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/boilerplate.go.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/clientset.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package versioned
20 |
21 | import (
22 | "fmt"
23 |
24 | stablev1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1"
25 | discovery "k8s.io/client-go/discovery"
26 | rest "k8s.io/client-go/rest"
27 | flowcontrol "k8s.io/client-go/util/flowcontrol"
28 | )
29 |
30 | type Interface interface {
31 | Discovery() discovery.DiscoveryInterface
32 | StableV1() stablev1.StableV1Interface
33 | }
34 |
35 | // Clientset contains the clients for groups. Each group has exactly one
36 | // version included in a Clientset.
37 | type Clientset struct {
38 | *discovery.DiscoveryClient
39 | stableV1 *stablev1.StableV1Client
40 | }
41 |
42 | // StableV1 retrieves the StableV1Client
43 | func (c *Clientset) StableV1() stablev1.StableV1Interface {
44 | return c.stableV1
45 | }
46 |
47 | // Discovery retrieves the DiscoveryClient
48 | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
49 | if c == nil {
50 | return nil
51 | }
52 | return c.DiscoveryClient
53 | }
54 |
55 | // NewForConfig creates a new Clientset for the given config.
56 | // If config's RateLimiter is not set and QPS and Burst are acceptable,
57 | // NewForConfig will generate a rate-limiter in configShallowCopy.
58 | func NewForConfig(c *rest.Config) (*Clientset, error) {
59 | configShallowCopy := *c
60 | if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
61 | if configShallowCopy.Burst <= 0 {
62 | return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
63 | }
64 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
65 | }
66 | var cs Clientset
67 | var err error
68 | cs.stableV1, err = stablev1.NewForConfig(&configShallowCopy)
69 | if err != nil {
70 | return nil, err
71 | }
72 |
73 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
74 | if err != nil {
75 | return nil, err
76 | }
77 | return &cs, nil
78 | }
79 |
80 | // NewForConfigOrDie creates a new Clientset for the given config and
81 | // panics if there is an error in the config.
82 | func NewForConfigOrDie(c *rest.Config) *Clientset {
83 | var cs Clientset
84 | cs.stableV1 = stablev1.NewForConfigOrDie(c)
85 |
86 | cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
87 | return &cs
88 | }
89 |
90 | // New creates a new Clientset for the given RESTClient.
91 | func New(c rest.Interface) *Clientset {
92 | var cs Clientset
93 | cs.stableV1 = stablev1.New(c)
94 |
95 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
96 | return &cs
97 | }
98 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package has the automatically generated clientset.
20 | package versioned
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/fake/clientset_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | clientset "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned"
23 | stablev1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1"
24 | fakestablev1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1/fake"
25 | "k8s.io/apimachinery/pkg/runtime"
26 | "k8s.io/apimachinery/pkg/watch"
27 | "k8s.io/client-go/discovery"
28 | fakediscovery "k8s.io/client-go/discovery/fake"
29 | "k8s.io/client-go/testing"
30 | )
31 |
32 | // NewSimpleClientset returns a clientset that will respond with the provided objects.
33 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
34 | // without applying any validations and/or defaults. It shouldn't be considered a replacement
35 | // for a real clientset and is mostly useful in simple unit tests.
36 | func NewSimpleClientset(objects ...runtime.Object) *Clientset {
37 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
38 | for _, obj := range objects {
39 | if err := o.Add(obj); err != nil {
40 | panic(err)
41 | }
42 | }
43 |
44 | cs := &Clientset{tracker: o}
45 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
46 | cs.AddReactor("*", "*", testing.ObjectReaction(o))
47 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
48 | gvr := action.GetResource()
49 | ns := action.GetNamespace()
50 | watch, err := o.Watch(gvr, ns)
51 | if err != nil {
52 | return false, nil, err
53 | }
54 | return true, watch, nil
55 | })
56 |
57 | return cs
58 | }
59 |
60 | // Clientset implements clientset.Interface. Meant to be embedded into a
61 | // struct to get a default implementation. This makes faking out just the method
62 | // you want to test easier.
63 | type Clientset struct {
64 | testing.Fake
65 | discovery *fakediscovery.FakeDiscovery
66 | tracker testing.ObjectTracker
67 | }
68 |
69 | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
70 | return c.discovery
71 | }
72 |
73 | func (c *Clientset) Tracker() testing.ObjectTracker {
74 | return c.tracker
75 | }
76 |
77 | var _ clientset.Interface = &Clientset{}
78 |
79 | // StableV1 retrieves the StableV1Client
80 | func (c *Clientset) StableV1() stablev1.StableV1Interface {
81 | return &fakestablev1.FakeStableV1{Fake: &c.Fake}
82 | }
83 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package has the automatically generated fake clientset.
20 | package fake
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/fake/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | stablev1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 | runtime "k8s.io/apimachinery/pkg/runtime"
25 | schema "k8s.io/apimachinery/pkg/runtime/schema"
26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
27 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
28 | )
29 |
30 | var scheme = runtime.NewScheme()
31 | var codecs = serializer.NewCodecFactory(scheme)
32 |
33 | var localSchemeBuilder = runtime.SchemeBuilder{
34 | stablev1.AddToScheme,
35 | }
36 |
37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
38 | // of clientsets, like in:
39 | //
40 | // import (
41 | // "k8s.io/client-go/kubernetes"
42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
44 | // )
45 | //
46 | // kclientset, _ := kubernetes.NewForConfig(c)
47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
48 | //
49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
50 | // correctly.
51 | var AddToScheme = localSchemeBuilder.AddToScheme
52 |
53 | func init() {
54 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
55 | utilruntime.Must(AddToScheme(scheme))
56 | }
57 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/scheme/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package contains the scheme of the automatically generated clientset.
20 | package scheme
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/scheme/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package scheme
20 |
21 | import (
22 | stablev1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 | runtime "k8s.io/apimachinery/pkg/runtime"
25 | schema "k8s.io/apimachinery/pkg/runtime/schema"
26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
27 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
28 | )
29 |
30 | var Scheme = runtime.NewScheme()
31 | var Codecs = serializer.NewCodecFactory(Scheme)
32 | var ParameterCodec = runtime.NewParameterCodec(Scheme)
33 | var localSchemeBuilder = runtime.SchemeBuilder{
34 | stablev1.AddToScheme,
35 | }
36 |
37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
38 | // of clientsets, like in:
39 | //
40 | // import (
41 | // "k8s.io/client-go/kubernetes"
42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
44 | // )
45 | //
46 | // kclientset, _ := kubernetes.NewForConfig(c)
47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
48 | //
49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
50 | // correctly.
51 | var AddToScheme = localSchemeBuilder.AddToScheme
52 |
53 | func init() {
54 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
55 | utilruntime.Must(AddToScheme(Scheme))
56 | }
57 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package has the automatically generated typed clients.
20 | package v1
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // Package fake has the automatically generated clients.
20 | package fake
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1/fake/fake_rabbit.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | "context"
23 |
24 | stablewbsnailcomv1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 | labels "k8s.io/apimachinery/pkg/labels"
27 | schema "k8s.io/apimachinery/pkg/runtime/schema"
28 | types "k8s.io/apimachinery/pkg/types"
29 | watch "k8s.io/apimachinery/pkg/watch"
30 | testing "k8s.io/client-go/testing"
31 | )
32 |
33 | // FakeRabbits implements RabbitInterface
34 | type FakeRabbits struct {
35 | Fake *FakeStableV1
36 | ns string
37 | }
38 |
39 | var rabbitsResource = schema.GroupVersionResource{Group: "stable.wbsnail.com", Version: "v1", Resource: "rabbits"}
40 |
41 | var rabbitsKind = schema.GroupVersionKind{Group: "stable.wbsnail.com", Version: "v1", Kind: "Rabbit"}
42 |
43 | // Get takes name of the rabbit, and returns the corresponding rabbit object, and an error if there is any.
44 | func (c *FakeRabbits) Get(ctx context.Context, name string, options v1.GetOptions) (result *stablewbsnailcomv1.Rabbit, err error) {
45 | obj, err := c.Fake.
46 | Invokes(testing.NewGetAction(rabbitsResource, c.ns, name), &stablewbsnailcomv1.Rabbit{})
47 |
48 | if obj == nil {
49 | return nil, err
50 | }
51 | return obj.(*stablewbsnailcomv1.Rabbit), err
52 | }
53 |
54 | // List takes label and field selectors, and returns the list of Rabbits that match those selectors.
55 | func (c *FakeRabbits) List(ctx context.Context, opts v1.ListOptions) (result *stablewbsnailcomv1.RabbitList, err error) {
56 | obj, err := c.Fake.
57 | Invokes(testing.NewListAction(rabbitsResource, rabbitsKind, c.ns, opts), &stablewbsnailcomv1.RabbitList{})
58 |
59 | if obj == nil {
60 | return nil, err
61 | }
62 |
63 | label, _, _ := testing.ExtractFromListOptions(opts)
64 | if label == nil {
65 | label = labels.Everything()
66 | }
67 | list := &stablewbsnailcomv1.RabbitList{ListMeta: obj.(*stablewbsnailcomv1.RabbitList).ListMeta}
68 | for _, item := range obj.(*stablewbsnailcomv1.RabbitList).Items {
69 | if label.Matches(labels.Set(item.Labels)) {
70 | list.Items = append(list.Items, item)
71 | }
72 | }
73 | return list, err
74 | }
75 |
76 | // Watch returns a watch.Interface that watches the requested rabbits.
77 | func (c *FakeRabbits) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
78 | return c.Fake.
79 | InvokesWatch(testing.NewWatchAction(rabbitsResource, c.ns, opts))
80 |
81 | }
82 |
83 | // Create takes the representation of a rabbit and creates it. Returns the server's representation of the rabbit, and an error, if there is any.
84 | func (c *FakeRabbits) Create(ctx context.Context, rabbit *stablewbsnailcomv1.Rabbit, opts v1.CreateOptions) (result *stablewbsnailcomv1.Rabbit, err error) {
85 | obj, err := c.Fake.
86 | Invokes(testing.NewCreateAction(rabbitsResource, c.ns, rabbit), &stablewbsnailcomv1.Rabbit{})
87 |
88 | if obj == nil {
89 | return nil, err
90 | }
91 | return obj.(*stablewbsnailcomv1.Rabbit), err
92 | }
93 |
94 | // Update takes the representation of a rabbit and updates it. Returns the server's representation of the rabbit, and an error, if there is any.
95 | func (c *FakeRabbits) Update(ctx context.Context, rabbit *stablewbsnailcomv1.Rabbit, opts v1.UpdateOptions) (result *stablewbsnailcomv1.Rabbit, err error) {
96 | obj, err := c.Fake.
97 | Invokes(testing.NewUpdateAction(rabbitsResource, c.ns, rabbit), &stablewbsnailcomv1.Rabbit{})
98 |
99 | if obj == nil {
100 | return nil, err
101 | }
102 | return obj.(*stablewbsnailcomv1.Rabbit), err
103 | }
104 |
105 | // Delete takes name of the rabbit and deletes it. Returns an error if one occurs.
106 | func (c *FakeRabbits) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
107 | _, err := c.Fake.
108 | Invokes(testing.NewDeleteAction(rabbitsResource, c.ns, name), &stablewbsnailcomv1.Rabbit{})
109 |
110 | return err
111 | }
112 |
113 | // DeleteCollection deletes a collection of objects.
114 | func (c *FakeRabbits) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
115 | action := testing.NewDeleteCollectionAction(rabbitsResource, c.ns, listOpts)
116 |
117 | _, err := c.Fake.Invokes(action, &stablewbsnailcomv1.RabbitList{})
118 | return err
119 | }
120 |
121 | // Patch applies the patch and returns the patched rabbit.
122 | func (c *FakeRabbits) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *stablewbsnailcomv1.Rabbit, err error) {
123 | obj, err := c.Fake.
124 | Invokes(testing.NewPatchSubresourceAction(rabbitsResource, c.ns, name, pt, data, subresources...), &stablewbsnailcomv1.Rabbit{})
125 |
126 | if obj == nil {
127 | return nil, err
128 | }
129 | return obj.(*stablewbsnailcomv1.Rabbit), err
130 | }
131 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1/fake/fake_stable.wbsnail.com_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | v1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1"
23 | rest "k8s.io/client-go/rest"
24 | testing "k8s.io/client-go/testing"
25 | )
26 |
27 | type FakeStableV1 struct {
28 | *testing.Fake
29 | }
30 |
31 | func (c *FakeStableV1) Rabbits(namespace string) v1.RabbitInterface {
32 | return &FakeRabbits{c, namespace}
33 | }
34 |
35 | // RESTClient returns a RESTClient that is used to communicate
36 | // with API server by this client implementation.
37 | func (c *FakeStableV1) RESTClient() rest.Interface {
38 | var ret *rest.RESTClient
39 | return ret
40 | }
41 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1/generated_expansion.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | type RabbitExpansion interface{}
22 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1/rabbit.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | "context"
23 | "time"
24 |
25 | v1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
26 | scheme "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/scheme"
27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 | types "k8s.io/apimachinery/pkg/types"
29 | watch "k8s.io/apimachinery/pkg/watch"
30 | rest "k8s.io/client-go/rest"
31 | )
32 |
33 | // RabbitsGetter has a method to return a RabbitInterface.
34 | // A group's client should implement this interface.
35 | type RabbitsGetter interface {
36 | Rabbits(namespace string) RabbitInterface
37 | }
38 |
39 | // RabbitInterface has methods to work with Rabbit resources.
40 | type RabbitInterface interface {
41 | Create(ctx context.Context, rabbit *v1.Rabbit, opts metav1.CreateOptions) (*v1.Rabbit, error)
42 | Update(ctx context.Context, rabbit *v1.Rabbit, opts metav1.UpdateOptions) (*v1.Rabbit, error)
43 | Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
44 | DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
45 | Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Rabbit, error)
46 | List(ctx context.Context, opts metav1.ListOptions) (*v1.RabbitList, error)
47 | Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
48 | Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Rabbit, err error)
49 | RabbitExpansion
50 | }
51 |
52 | // rabbits implements RabbitInterface
53 | type rabbits struct {
54 | client rest.Interface
55 | ns string
56 | }
57 |
58 | // newRabbits returns a Rabbits
59 | func newRabbits(c *StableV1Client, namespace string) *rabbits {
60 | return &rabbits{
61 | client: c.RESTClient(),
62 | ns: namespace,
63 | }
64 | }
65 |
66 | // Get takes name of the rabbit, and returns the corresponding rabbit object, and an error if there is any.
67 | func (c *rabbits) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Rabbit, err error) {
68 | result = &v1.Rabbit{}
69 | err = c.client.Get().
70 | Namespace(c.ns).
71 | Resource("rabbits").
72 | Name(name).
73 | VersionedParams(&options, scheme.ParameterCodec).
74 | Do(ctx).
75 | Into(result)
76 | return
77 | }
78 |
79 | // List takes label and field selectors, and returns the list of Rabbits that match those selectors.
80 | func (c *rabbits) List(ctx context.Context, opts metav1.ListOptions) (result *v1.RabbitList, err error) {
81 | var timeout time.Duration
82 | if opts.TimeoutSeconds != nil {
83 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
84 | }
85 | result = &v1.RabbitList{}
86 | err = c.client.Get().
87 | Namespace(c.ns).
88 | Resource("rabbits").
89 | VersionedParams(&opts, scheme.ParameterCodec).
90 | Timeout(timeout).
91 | Do(ctx).
92 | Into(result)
93 | return
94 | }
95 |
96 | // Watch returns a watch.Interface that watches the requested rabbits.
97 | func (c *rabbits) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
98 | var timeout time.Duration
99 | if opts.TimeoutSeconds != nil {
100 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
101 | }
102 | opts.Watch = true
103 | return c.client.Get().
104 | Namespace(c.ns).
105 | Resource("rabbits").
106 | VersionedParams(&opts, scheme.ParameterCodec).
107 | Timeout(timeout).
108 | Watch(ctx)
109 | }
110 |
111 | // Create takes the representation of a rabbit and creates it. Returns the server's representation of the rabbit, and an error, if there is any.
112 | func (c *rabbits) Create(ctx context.Context, rabbit *v1.Rabbit, opts metav1.CreateOptions) (result *v1.Rabbit, err error) {
113 | result = &v1.Rabbit{}
114 | err = c.client.Post().
115 | Namespace(c.ns).
116 | Resource("rabbits").
117 | VersionedParams(&opts, scheme.ParameterCodec).
118 | Body(rabbit).
119 | Do(ctx).
120 | Into(result)
121 | return
122 | }
123 |
124 | // Update takes the representation of a rabbit and updates it. Returns the server's representation of the rabbit, and an error, if there is any.
125 | func (c *rabbits) Update(ctx context.Context, rabbit *v1.Rabbit, opts metav1.UpdateOptions) (result *v1.Rabbit, err error) {
126 | result = &v1.Rabbit{}
127 | err = c.client.Put().
128 | Namespace(c.ns).
129 | Resource("rabbits").
130 | Name(rabbit.Name).
131 | VersionedParams(&opts, scheme.ParameterCodec).
132 | Body(rabbit).
133 | Do(ctx).
134 | Into(result)
135 | return
136 | }
137 |
138 | // Delete takes name of the rabbit and deletes it. Returns an error if one occurs.
139 | func (c *rabbits) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
140 | return c.client.Delete().
141 | Namespace(c.ns).
142 | Resource("rabbits").
143 | Name(name).
144 | Body(&opts).
145 | Do(ctx).
146 | Error()
147 | }
148 |
149 | // DeleteCollection deletes a collection of objects.
150 | func (c *rabbits) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
151 | var timeout time.Duration
152 | if listOpts.TimeoutSeconds != nil {
153 | timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
154 | }
155 | return c.client.Delete().
156 | Namespace(c.ns).
157 | Resource("rabbits").
158 | VersionedParams(&listOpts, scheme.ParameterCodec).
159 | Timeout(timeout).
160 | Body(&opts).
161 | Do(ctx).
162 | Error()
163 | }
164 |
165 | // Patch applies the patch and returns the patched rabbit.
166 | func (c *rabbits) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Rabbit, err error) {
167 | result = &v1.Rabbit{}
168 | err = c.client.Patch(pt).
169 | Namespace(c.ns).
170 | Resource("rabbits").
171 | Name(name).
172 | SubResource(subresources...).
173 | VersionedParams(&opts, scheme.ParameterCodec).
174 | Body(data).
175 | Do(ctx).
176 | Into(result)
177 | return
178 | }
179 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/typed/stable.wbsnail.com/v1/stable.wbsnail.com_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | v1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
23 | "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned/scheme"
24 | rest "k8s.io/client-go/rest"
25 | )
26 |
27 | type StableV1Interface interface {
28 | RESTClient() rest.Interface
29 | RabbitsGetter
30 | }
31 |
32 | // StableV1Client is used to interact with features provided by the stable.wbsnail.com group.
33 | type StableV1Client struct {
34 | restClient rest.Interface
35 | }
36 |
37 | func (c *StableV1Client) Rabbits(namespace string) RabbitInterface {
38 | return newRabbits(c, namespace)
39 | }
40 |
41 | // NewForConfig creates a new StableV1Client for the given config.
42 | func NewForConfig(c *rest.Config) (*StableV1Client, error) {
43 | config := *c
44 | if err := setConfigDefaults(&config); err != nil {
45 | return nil, err
46 | }
47 | client, err := rest.RESTClientFor(&config)
48 | if err != nil {
49 | return nil, err
50 | }
51 | return &StableV1Client{client}, nil
52 | }
53 |
54 | // NewForConfigOrDie creates a new StableV1Client for the given config and
55 | // panics if there is an error in the config.
56 | func NewForConfigOrDie(c *rest.Config) *StableV1Client {
57 | client, err := NewForConfig(c)
58 | if err != nil {
59 | panic(err)
60 | }
61 | return client
62 | }
63 |
64 | // New creates a new StableV1Client for the given RESTClient.
65 | func New(c rest.Interface) *StableV1Client {
66 | return &StableV1Client{c}
67 | }
68 |
69 | func setConfigDefaults(config *rest.Config) error {
70 | gv := v1.SchemeGroupVersion
71 | config.GroupVersion = &gv
72 | config.APIPath = "/apis"
73 | config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
74 |
75 | if config.UserAgent == "" {
76 | config.UserAgent = rest.DefaultKubernetesUserAgent()
77 | }
78 |
79 | return nil
80 | }
81 |
82 | // RESTClient returns a RESTClient that is used to communicate
83 | // with API server by this client implementation.
84 | func (c *StableV1Client) RESTClient() rest.Interface {
85 | if c == nil {
86 | return nil
87 | }
88 | return c.restClient
89 | }
90 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/factory.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package externalversions
20 |
21 | import (
22 | reflect "reflect"
23 | sync "sync"
24 | time "time"
25 |
26 | versioned "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned"
27 | internalinterfaces "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/internalinterfaces"
28 | stablewbsnailcom "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/stable.wbsnail.com"
29 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 | runtime "k8s.io/apimachinery/pkg/runtime"
31 | schema "k8s.io/apimachinery/pkg/runtime/schema"
32 | cache "k8s.io/client-go/tools/cache"
33 | )
34 |
35 | // SharedInformerOption defines the functional option type for SharedInformerFactory.
36 | type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory
37 |
38 | type sharedInformerFactory struct {
39 | client versioned.Interface
40 | namespace string
41 | tweakListOptions internalinterfaces.TweakListOptionsFunc
42 | lock sync.Mutex
43 | defaultResync time.Duration
44 | customResync map[reflect.Type]time.Duration
45 |
46 | informers map[reflect.Type]cache.SharedIndexInformer
47 | // startedInformers is used for tracking which informers have been started.
48 | // This allows Start() to be called multiple times safely.
49 | startedInformers map[reflect.Type]bool
50 | }
51 |
52 | // WithCustomResyncConfig sets a custom resync period for the specified informer types.
53 | func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption {
54 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
55 | for k, v := range resyncConfig {
56 | factory.customResync[reflect.TypeOf(k)] = v
57 | }
58 | return factory
59 | }
60 | }
61 |
62 | // WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory.
63 | func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption {
64 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
65 | factory.tweakListOptions = tweakListOptions
66 | return factory
67 | }
68 | }
69 |
70 | // WithNamespace limits the SharedInformerFactory to the specified namespace.
71 | func WithNamespace(namespace string) SharedInformerOption {
72 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
73 | factory.namespace = namespace
74 | return factory
75 | }
76 | }
77 |
78 | // NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
79 | func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
80 | return NewSharedInformerFactoryWithOptions(client, defaultResync)
81 | }
82 |
83 | // NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
84 | // Listers obtained via this SharedInformerFactory will be subject to the same filters
85 | // as specified here.
86 | // Deprecated: Please use NewSharedInformerFactoryWithOptions instead
87 | func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
88 | return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions))
89 | }
90 |
91 | // NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
92 | func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory {
93 | factory := &sharedInformerFactory{
94 | client: client,
95 | namespace: v1.NamespaceAll,
96 | defaultResync: defaultResync,
97 | informers: make(map[reflect.Type]cache.SharedIndexInformer),
98 | startedInformers: make(map[reflect.Type]bool),
99 | customResync: make(map[reflect.Type]time.Duration),
100 | }
101 |
102 | // Apply all options
103 | for _, opt := range options {
104 | factory = opt(factory)
105 | }
106 |
107 | return factory
108 | }
109 |
110 | // Start initializes all requested informers.
111 | func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
112 | f.lock.Lock()
113 | defer f.lock.Unlock()
114 |
115 | for informerType, informer := range f.informers {
116 | if !f.startedInformers[informerType] {
117 | go informer.Run(stopCh)
118 | f.startedInformers[informerType] = true
119 | }
120 | }
121 | }
122 |
123 | // WaitForCacheSync waits for all started informers' cache were synced.
124 | func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
125 | informers := func() map[reflect.Type]cache.SharedIndexInformer {
126 | f.lock.Lock()
127 | defer f.lock.Unlock()
128 |
129 | informers := map[reflect.Type]cache.SharedIndexInformer{}
130 | for informerType, informer := range f.informers {
131 | if f.startedInformers[informerType] {
132 | informers[informerType] = informer
133 | }
134 | }
135 | return informers
136 | }()
137 |
138 | res := map[reflect.Type]bool{}
139 | for informType, informer := range informers {
140 | res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
141 | }
142 | return res
143 | }
144 |
145 | // InternalInformerFor returns the SharedIndexInformer for obj using an internal
146 | // client.
147 | func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
148 | f.lock.Lock()
149 | defer f.lock.Unlock()
150 |
151 | informerType := reflect.TypeOf(obj)
152 | informer, exists := f.informers[informerType]
153 | if exists {
154 | return informer
155 | }
156 |
157 | resyncPeriod, exists := f.customResync[informerType]
158 | if !exists {
159 | resyncPeriod = f.defaultResync
160 | }
161 |
162 | informer = newFunc(f.client, resyncPeriod)
163 | f.informers[informerType] = informer
164 |
165 | return informer
166 | }
167 |
168 | // SharedInformerFactory provides shared informers for resources in all known
169 | // API group versions.
170 | type SharedInformerFactory interface {
171 | internalinterfaces.SharedInformerFactory
172 | ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
173 | WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
174 |
175 | Stable() stablewbsnailcom.Interface
176 | }
177 |
178 | func (f *sharedInformerFactory) Stable() stablewbsnailcom.Interface {
179 | return stablewbsnailcom.New(f, f.namespace, f.tweakListOptions)
180 | }
181 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/generic.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package externalversions
20 |
21 | import (
22 | "fmt"
23 |
24 | v1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
25 | schema "k8s.io/apimachinery/pkg/runtime/schema"
26 | cache "k8s.io/client-go/tools/cache"
27 | )
28 |
29 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other
30 | // sharedInformers based on type
31 | type GenericInformer interface {
32 | Informer() cache.SharedIndexInformer
33 | Lister() cache.GenericLister
34 | }
35 |
36 | type genericInformer struct {
37 | informer cache.SharedIndexInformer
38 | resource schema.GroupResource
39 | }
40 |
41 | // Informer returns the SharedIndexInformer.
42 | func (f *genericInformer) Informer() cache.SharedIndexInformer {
43 | return f.informer
44 | }
45 |
46 | // Lister returns the GenericLister.
47 | func (f *genericInformer) Lister() cache.GenericLister {
48 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
49 | }
50 |
51 | // ForResource gives generic access to a shared informer of the matching type
52 | // TODO extend this to unknown resources with a client pool
53 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
54 | switch resource {
55 | // Group=stable.wbsnail.com, Version=v1
56 | case v1.SchemeGroupVersion.WithResource("rabbits"):
57 | return &genericInformer{resource: resource.GroupResource(), informer: f.Stable().V1().Rabbits().Informer()}, nil
58 |
59 | }
60 |
61 | return nil, fmt.Errorf("no informer found for %v", resource)
62 | }
63 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/internalinterfaces/factory_interfaces.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package internalinterfaces
20 |
21 | import (
22 | time "time"
23 |
24 | versioned "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned"
25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 | runtime "k8s.io/apimachinery/pkg/runtime"
27 | cache "k8s.io/client-go/tools/cache"
28 | )
29 |
30 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
31 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
32 |
33 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle
34 | type SharedInformerFactory interface {
35 | Start(stopCh <-chan struct{})
36 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
37 | }
38 |
39 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions.
40 | type TweakListOptionsFunc func(*v1.ListOptions)
41 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/stable.wbsnail.com/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package stable
20 |
21 | import (
22 | internalinterfaces "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/internalinterfaces"
23 | v1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/stable.wbsnail.com/v1"
24 | )
25 |
26 | // Interface provides access to each of this group's versions.
27 | type Interface interface {
28 | // V1 provides access to shared informers for resources in V1.
29 | V1() v1.Interface
30 | }
31 |
32 | type group struct {
33 | factory internalinterfaces.SharedInformerFactory
34 | namespace string
35 | tweakListOptions internalinterfaces.TweakListOptionsFunc
36 | }
37 |
38 | // New returns a new Interface.
39 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
40 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
41 | }
42 |
43 | // V1 returns a new v1.Interface.
44 | func (g *group) V1() v1.Interface {
45 | return v1.New(g.factory, g.namespace, g.tweakListOptions)
46 | }
47 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/stable.wbsnail.com/v1/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | internalinterfaces "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/internalinterfaces"
23 | )
24 |
25 | // Interface provides access to all the informers in this group version.
26 | type Interface interface {
27 | // Rabbits returns a RabbitInformer.
28 | Rabbits() RabbitInformer
29 | }
30 |
31 | type version struct {
32 | factory internalinterfaces.SharedInformerFactory
33 | namespace string
34 | tweakListOptions internalinterfaces.TweakListOptionsFunc
35 | }
36 |
37 | // New returns a new Interface.
38 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
39 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
40 | }
41 |
42 | // Rabbits returns a RabbitInformer.
43 | func (v *version) Rabbits() RabbitInformer {
44 | return &rabbitInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
45 | }
46 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/stable.wbsnail.com/v1/rabbit.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | "context"
23 | time "time"
24 |
25 | stablewbsnailcomv1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
26 | versioned "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned"
27 | internalinterfaces "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions/internalinterfaces"
28 | v1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/listers/stable.wbsnail.com/v1"
29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 | runtime "k8s.io/apimachinery/pkg/runtime"
31 | watch "k8s.io/apimachinery/pkg/watch"
32 | cache "k8s.io/client-go/tools/cache"
33 | )
34 |
35 | // RabbitInformer provides access to a shared informer and lister for
36 | // Rabbits.
37 | type RabbitInformer interface {
38 | Informer() cache.SharedIndexInformer
39 | Lister() v1.RabbitLister
40 | }
41 |
42 | type rabbitInformer struct {
43 | factory internalinterfaces.SharedInformerFactory
44 | tweakListOptions internalinterfaces.TweakListOptionsFunc
45 | namespace string
46 | }
47 |
48 | // NewRabbitInformer constructs a new informer for Rabbit type.
49 | // Always prefer using an informer factory to get a shared informer instead of getting an independent
50 | // one. This reduces memory footprint and number of connections to the server.
51 | func NewRabbitInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
52 | return NewFilteredRabbitInformer(client, namespace, resyncPeriod, indexers, nil)
53 | }
54 |
55 | // NewFilteredRabbitInformer constructs a new informer for Rabbit type.
56 | // Always prefer using an informer factory to get a shared informer instead of getting an independent
57 | // one. This reduces memory footprint and number of connections to the server.
58 | func NewFilteredRabbitInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
59 | return cache.NewSharedIndexInformer(
60 | &cache.ListWatch{
61 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
62 | if tweakListOptions != nil {
63 | tweakListOptions(&options)
64 | }
65 | return client.StableV1().Rabbits(namespace).List(context.TODO(), options)
66 | },
67 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
68 | if tweakListOptions != nil {
69 | tweakListOptions(&options)
70 | }
71 | return client.StableV1().Rabbits(namespace).Watch(context.TODO(), options)
72 | },
73 | },
74 | &stablewbsnailcomv1.Rabbit{},
75 | resyncPeriod,
76 | indexers,
77 | )
78 | }
79 |
80 | func (f *rabbitInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
81 | return NewFilteredRabbitInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
82 | }
83 |
84 | func (f *rabbitInformer) Informer() cache.SharedIndexInformer {
85 | return f.factory.InformerFor(&stablewbsnailcomv1.Rabbit{}, f.defaultInformer)
86 | }
87 |
88 | func (f *rabbitInformer) Lister() v1.RabbitLister {
89 | return v1.NewRabbitLister(f.Informer().GetIndexer())
90 | }
91 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/listers/stable.wbsnail.com/v1/expansion_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by lister-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | // RabbitListerExpansion allows custom methods to be added to
22 | // RabbitLister.
23 | type RabbitListerExpansion interface{}
24 |
25 | // RabbitNamespaceListerExpansion allows custom methods to be added to
26 | // RabbitNamespaceLister.
27 | type RabbitNamespaceListerExpansion interface{}
28 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/client/listers/stable.wbsnail.com/v1/rabbit.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright wbsnail.com.
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 | // Code generated by lister-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | v1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
23 | "k8s.io/apimachinery/pkg/api/errors"
24 | "k8s.io/apimachinery/pkg/labels"
25 | "k8s.io/client-go/tools/cache"
26 | )
27 |
28 | // RabbitLister helps list Rabbits.
29 | // All objects returned here must be treated as read-only.
30 | type RabbitLister interface {
31 | // List lists all Rabbits in the indexer.
32 | // Objects returned here must be treated as read-only.
33 | List(selector labels.Selector) (ret []*v1.Rabbit, err error)
34 | // Rabbits returns an object that can list and get Rabbits.
35 | Rabbits(namespace string) RabbitNamespaceLister
36 | RabbitListerExpansion
37 | }
38 |
39 | // rabbitLister implements the RabbitLister interface.
40 | type rabbitLister struct {
41 | indexer cache.Indexer
42 | }
43 |
44 | // NewRabbitLister returns a new RabbitLister.
45 | func NewRabbitLister(indexer cache.Indexer) RabbitLister {
46 | return &rabbitLister{indexer: indexer}
47 | }
48 |
49 | // List lists all Rabbits in the indexer.
50 | func (s *rabbitLister) List(selector labels.Selector) (ret []*v1.Rabbit, err error) {
51 | err = cache.ListAll(s.indexer, selector, func(m interface{}) {
52 | ret = append(ret, m.(*v1.Rabbit))
53 | })
54 | return ret, err
55 | }
56 |
57 | // Rabbits returns an object that can list and get Rabbits.
58 | func (s *rabbitLister) Rabbits(namespace string) RabbitNamespaceLister {
59 | return rabbitNamespaceLister{indexer: s.indexer, namespace: namespace}
60 | }
61 |
62 | // RabbitNamespaceLister helps list and get Rabbits.
63 | // All objects returned here must be treated as read-only.
64 | type RabbitNamespaceLister interface {
65 | // List lists all Rabbits in the indexer for a given namespace.
66 | // Objects returned here must be treated as read-only.
67 | List(selector labels.Selector) (ret []*v1.Rabbit, err error)
68 | // Get retrieves the Rabbit from the indexer for a given namespace and name.
69 | // Objects returned here must be treated as read-only.
70 | Get(name string) (*v1.Rabbit, error)
71 | RabbitNamespaceListerExpansion
72 | }
73 |
74 | // rabbitNamespaceLister implements the RabbitNamespaceLister
75 | // interface.
76 | type rabbitNamespaceLister struct {
77 | indexer cache.Indexer
78 | namespace string
79 | }
80 |
81 | // List lists all Rabbits in the indexer for a given namespace.
82 | func (s rabbitNamespaceLister) List(selector labels.Selector) (ret []*v1.Rabbit, err error) {
83 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
84 | ret = append(ret, m.(*v1.Rabbit))
85 | })
86 | return ret, err
87 | }
88 |
89 | // Get retrieves the Rabbit from the indexer for a given namespace and name.
90 | func (s rabbitNamespaceLister) Get(name string) (*v1.Rabbit, error) {
91 | obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
92 | if err != nil {
93 | return nil, err
94 | }
95 | if !exists {
96 | return nil, errors.NewNotFound(v1.Resource("rabbit"), name)
97 | }
98 | return obj.(*v1.Rabbit), nil
99 | }
100 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/crd.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apiextensions.k8s.io/v1
2 | kind: CustomResourceDefinition
3 | metadata:
4 | name: rabbits.stable.wbsnail.com
5 | spec:
6 | group: stable.wbsnail.com
7 | versions:
8 | - name: v1
9 | served: true
10 | storage: true
11 | schema:
12 | openAPIV3Schema:
13 | type: object
14 | properties:
15 | spec:
16 | type: object
17 | properties:
18 | color:
19 | type: string
20 | additionalPrinterColumns:
21 | - name: Color
22 | type: string
23 | description: Color
24 | jsonPath: .spec.color
25 | - name: Age
26 | type: date
27 | description: Age
28 | jsonPath: .metadata.creationTimestamp
29 | scope: Namespaced
30 | names:
31 | plural: rabbits
32 | singular: rabbit
33 | kind: Rabbit
34 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/custom-resource.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "stable.wbsnail.com/v1"
2 | kind: Rabbit
3 | metadata:
4 | name: judy
5 | namespace: tmp
6 | spec:
7 | color: white
8 | ---
9 | apiVersion: "stable.wbsnail.com/v1"
10 | kind: Rabbit
11 | metadata:
12 | name: bugs
13 | namespace: tmp
14 | spec:
15 | color: gray
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/generate-groups.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | scriptPath=${SCRIPT_PATH}
4 |
5 | if [ -z ${scriptPath} ]; then
6 | echo "Tell me, where is the file? (SCRIPT_PATH)"
7 | echo "Maybe 'export SCRIPT_PATH=~/projects/code-generator/generate-groups.sh'?"
8 | exit 1
9 | fi
10 |
11 | ${scriptPath} \
12 | all \
13 | github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client \
14 | github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api \
15 | stable.wbsnail.com:v1 \
16 | --go-header-file ./boilerplate.go.txt
17 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/11-crd-informer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/spongeprojects/magicconch"
6 | v1 "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/api/stable.wbsnail.com/v1"
7 | "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/clientset/versioned"
8 | "github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/11-crd-informer/client/informers/externalversions"
9 | "k8s.io/client-go/tools/cache"
10 | "k8s.io/client-go/tools/clientcmd"
11 | "os"
12 | )
13 |
14 | func main() {
15 | kubeconfig := os.Getenv("KUBECONFIG")
16 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
17 | magicconch.Must(err)
18 |
19 | clientset, err := versioned.NewForConfig(config)
20 | magicconch.Must(err)
21 |
22 | informerFactory := externalversions.NewSharedInformerFactory(clientset, 0)
23 | rabbitInformer := informerFactory.Stable().V1().Rabbits().Informer()
24 | rabbitInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
25 | AddFunc: func(obj interface{}) {
26 | rabbit, ok := obj.(*v1.Rabbit)
27 | if !ok {
28 | return
29 | }
30 | fmt.Printf("A rabbit is created: %s\n", rabbit.Name)
31 | },
32 | UpdateFunc: func(oldObj, newObj interface{}) {
33 | newRabbit, ok := oldObj.(*v1.Rabbit)
34 | if !ok {
35 | return
36 | }
37 | fmt.Printf("A rabbit is updated: %s\n", newRabbit.Name)
38 | },
39 | DeleteFunc: func(obj interface{}) {
40 | rabbit, ok := obj.(*v1.Rabbit)
41 | if !ok {
42 | return
43 | }
44 | fmt.Printf("A rabbit is deleted: %s\n", rabbit.Name)
45 | },
46 | })
47 |
48 | stopCh := make(chan struct{})
49 | defer close(stopCh)
50 |
51 | fmt.Println("Start syncing....")
52 |
53 | go informerFactory.Start(stopCh)
54 |
55 | <-stopCh
56 | }
57 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/12-dynamic-informer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/spongeprojects/magicconch"
6 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
7 | "k8s.io/apimachinery/pkg/runtime/schema"
8 | "k8s.io/client-go/dynamic"
9 | "k8s.io/client-go/dynamic/dynamicinformer"
10 | "k8s.io/client-go/tools/cache"
11 | "k8s.io/client-go/tools/clientcmd"
12 | "os"
13 | )
14 |
15 | func main() {
16 | if len(os.Args) < 2 {
17 | fmt.Println("resource missing")
18 | return
19 | }
20 | // 资源,比如 "configmaps.v1.", "deployments.v1.apps", "rabbits.v1.stable.wbsnail.com"
21 | resource := os.Args[1]
22 |
23 | kubeconfig := os.Getenv("KUBECONFIG")
24 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
25 | magicconch.Must(err)
26 |
27 | // 注意创建了 dynamicClient, 而不是 clientset
28 | dynamicClient, err := dynamic.NewForConfig(config)
29 | magicconch.Must(err)
30 |
31 | // 同样这里也是 DynamicSharedInformerFactory, 而不是 SharedInformerFactory
32 | informerFactory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(
33 | dynamicClient, 0, "tmp", nil)
34 |
35 | // 通过 schema 包提供的 ParseResourceArg 由资源描述字符串解析出 GroupVersionResource
36 | gvr, _ := schema.ParseResourceArg(resource)
37 | if gvr == nil {
38 | fmt.Println("cannot parse gvr")
39 | return
40 | }
41 | // 使用 gvr 动态生成 Informer
42 | informer := informerFactory.ForResource(*gvr).Informer()
43 | // 熟悉的代码,熟悉的味道,只是收到的 obj 类型好像不太一样
44 | informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
45 | AddFunc: func(obj interface{}) {
46 | // *unstructured.Unstructured 类是所有 Kubernetes 资源类型公共方法的抽象,
47 | // 提供所有对公共属性的访问方法,像 GetName, GetNamespace, GetLabels 等等,
48 | s, ok := obj.(*unstructured.Unstructured)
49 | if !ok {
50 | return
51 | }
52 | fmt.Printf("created: %s\n", s.GetName())
53 | },
54 | UpdateFunc: func(oldObj, newObj interface{}) {
55 | oldS, ok1 := oldObj.(*unstructured.Unstructured)
56 | newS, ok2 := newObj.(*unstructured.Unstructured)
57 | if !ok1 || !ok2 {
58 | return
59 | }
60 | // 要访问公共属性外的字段,可以借助 unstructured 包提供的一些助手方法:
61 | oldColor, ok1, err1 := unstructured.NestedString(oldS.Object, "spec", "color")
62 | newColor, ok2, err2 := unstructured.NestedString(newS.Object, "spec", "color")
63 | if !ok1 || !ok2 || err1 != nil || err2 != nil {
64 | fmt.Printf("updated: %s\n", newS.GetName())
65 | }
66 | fmt.Printf("updated: %s, old color: %s, new color: %s\n", newS.GetName(), oldColor, newColor)
67 | },
68 | DeleteFunc: func(obj interface{}) {
69 | s, ok := obj.(*unstructured.Unstructured)
70 | if !ok {
71 | return
72 | }
73 | fmt.Printf("deleted: %s\n", s.GetName())
74 | },
75 | })
76 |
77 | stopCh := make(chan struct{})
78 | defer close(stopCh)
79 |
80 | fmt.Println("Start syncing....")
81 |
82 | go informerFactory.Start(stopCh)
83 |
84 | <-stopCh
85 | }
86 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/2-reflector/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/2-reflector/lw.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/fields"
5 | "k8s.io/client-go/tools/cache"
6 | )
7 |
8 | // newConfigMapsListerWatcher 用于创建 tmp namespace 下 configmaps 资源的 ListerWatcher 实例
9 | func newConfigMapsListerWatcher() cache.ListerWatcher {
10 | clientset := mustClientset() // 前面有说明
11 | client := clientset.CoreV1().RESTClient() // 客户端,请求器
12 | resource := "configmaps" // GET 请求参数之一
13 | namespace := "tmp" // GET 请求参数之一
14 | selector := fields.Everything() // GET 请求参数之一
15 | lw := cache.NewListWatchFromClient(client, resource, namespace, selector)
16 | return lw
17 | }
18 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/2-reflector/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/spongeprojects/magicconch"
6 | corev1 "k8s.io/api/core/v1"
7 | "k8s.io/apimachinery/pkg/util/wait"
8 | "k8s.io/client-go/tools/cache"
9 | "time"
10 | )
11 |
12 | // newStore 用于创建一个 cache.Store 对象,作为当前资源状态的对象存储
13 | func newStore() cache.Store {
14 | return cache.NewStore(cache.MetaNamespaceKeyFunc)
15 | }
16 |
17 | // newQueue 用于创建一个 cache.Queue 对象,这里实现为 FIFO 先进先出队列,
18 | // 注意在初始化时 store 作为 KnownObjects 参数传入其中,
19 | // 因为在重新同步 (resync) 操作中 Reflector 需要知道当前的资源状态,
20 | // 另外在计算变更 (Delta) 时,也需要对比当前的资源状态。
21 | // 这个 KnownObjects 对队列,以及对 Reflector 都是只读的,用户需要自己维护好 store 的状态。
22 | func newQueue(store cache.Store) cache.Queue {
23 | return cache.NewDeltaFIFOWithOptions(cache.DeltaFIFOOptions{
24 | KnownObjects: store,
25 | EmitDeltaTypeReplaced: true,
26 | })
27 | }
28 |
29 | // newConfigMapsReflector 用于创建一个 cache.Reflector 对象,
30 | // 当 Reflector 开始运行 (Run) 后,队列中就会推入新收到的事件。
31 | func newConfigMapsReflector(queue cache.Queue) *cache.Reflector {
32 | lw := newConfigMapsListerWatcher() // 前面有说明
33 | // 第 2 个参数是 expectedType, 用此参数限制进入队列的事件,
34 | // 当然在 List 和 Watch 操作时返回的数据就只有一种类型,这个参数只起校验的作用;
35 | // 第 4 个参数是 resyncPeriod,
36 | // 这里传了 0,表示从不重新同步(除非连接超时或者中断),
37 | // 如果传了非 0 值,会定期进行全量同步,避免累积和服务器的不一致,
38 | // 同步过程中会产生 SYNC 类型的事件。
39 | return cache.NewReflector(lw, &corev1.ConfigMap{}, queue, 0)
40 | }
41 |
42 | func main() {
43 | fmt.Println("----- 2-reflector -----")
44 |
45 | store := newStore()
46 | queue := newQueue(store)
47 | reflector := newConfigMapsReflector(queue)
48 |
49 | stopCh := make(chan struct{})
50 | defer close(stopCh)
51 |
52 | // reflector 开始运行后,队列中就会推入新收到的事件
53 | go reflector.Run(stopCh)
54 |
55 | // 注意处理事件过程中维护好 store 状态,包括 Add, Update, Delete 操作,
56 | // 否则会出现不同步问题,在 Informer 当中这些逻辑都已经被封装好了,但目前我们还需要关心一下。
57 | processObj := func(obj interface{}) error {
58 | // 最先收到的事件会被最先处理
59 | for _, d := range obj.(cache.Deltas) {
60 | switch d.Type {
61 | case cache.Sync, cache.Replaced, cache.Added, cache.Updated:
62 | if _, exists, err := store.Get(d.Object); err == nil && exists {
63 | if err := store.Update(d.Object); err != nil {
64 | return err
65 | }
66 | } else {
67 | if err := store.Add(d.Object); err != nil {
68 | return err
69 | }
70 | }
71 | case cache.Deleted:
72 | if err := store.Delete(d.Object); err != nil {
73 | return err
74 | }
75 | }
76 | configMap, ok := d.Object.(*corev1.ConfigMap)
77 | if !ok {
78 | return fmt.Errorf("not config: %T", d.Object)
79 | }
80 | fmt.Printf("%s: %s\n", d.Type, configMap.Name)
81 | }
82 | return nil
83 | }
84 |
85 | fmt.Println("Start syncing...")
86 |
87 | // 持续运行直到 stopCh 关闭
88 | wait.Until(func() {
89 | for {
90 | _, err := queue.Pop(processObj)
91 | magicconch.Must(err)
92 | }
93 | }, time.Second, stopCh)
94 | }
95 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/3-controller/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/3-controller/lw.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/fields"
5 | "k8s.io/client-go/tools/cache"
6 | )
7 |
8 | // newConfigMapsListerWatcher 用于创建 tmp namespace 下 configmaps 资源的 ListerWatcher 实例
9 | func newConfigMapsListerWatcher() cache.ListerWatcher {
10 | clientset := mustClientset() // 前面有说明
11 | client := clientset.CoreV1().RESTClient() // 客户端,请求器
12 | resource := "configmaps" // GET 请求参数之一
13 | namespace := "tmp" // GET 请求参数之一
14 | selector := fields.Everything() // GET 请求参数之一
15 | lw := cache.NewListWatchFromClient(client, resource, namespace, selector)
16 | return lw
17 | }
18 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/3-controller/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | corev1 "k8s.io/api/core/v1"
6 | "k8s.io/client-go/tools/cache"
7 | )
8 |
9 | func newController() cache.Controller {
10 | fmt.Println("----- 3-controller -----")
11 |
12 | lw := newConfigMapsListerWatcher()
13 | store := newStore()
14 | queue := newQueue(store)
15 | cfg := &cache.Config{
16 | Queue: queue,
17 | ListerWatcher: lw,
18 | ObjectType: &corev1.ConfigMap{},
19 | FullResyncPeriod: 0,
20 | RetryOnError: false,
21 | Process: func(obj interface{}) error {
22 | for _, d := range obj.(cache.Deltas) {
23 | switch d.Type {
24 | case cache.Sync, cache.Replaced, cache.Added, cache.Updated:
25 | if _, exists, err := store.Get(d.Object); err == nil && exists {
26 | if err := store.Update(d.Object); err != nil {
27 | return err
28 | }
29 | } else {
30 | if err := store.Add(d.Object); err != nil {
31 | return err
32 | }
33 | }
34 | case cache.Deleted:
35 | if err := store.Delete(d.Object); err != nil {
36 | return err
37 | }
38 | }
39 | configMap, ok := d.Object.(*corev1.ConfigMap)
40 | if !ok {
41 | return fmt.Errorf("not config: %T", d.Object)
42 | }
43 | fmt.Printf("%s: %s\n", d.Type, configMap.Name)
44 | }
45 | return nil
46 | },
47 | }
48 | return cache.New(cfg)
49 | }
50 |
51 | func main() {
52 | controller := newController()
53 |
54 | stopCh := make(chan struct{})
55 | defer close(stopCh)
56 |
57 | fmt.Println("Start syncing....")
58 |
59 | go controller.Run(stopCh)
60 |
61 | <-stopCh
62 | }
63 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/3-controller/store.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "k8s.io/client-go/tools/cache"
5 | )
6 |
7 | // newStore 用于创建一个 cache.Store 对象,作为当前资源状态的对象存储
8 | func newStore() cache.Store {
9 | return cache.NewStore(cache.MetaNamespaceKeyFunc)
10 | }
11 |
12 | // newQueue 用于创建一个 cache.Queue 对象,这里实现为 FIFO 先进先出队列,
13 | // 注意在初始化时 store 作为 KnownObjects 参数传入其中,
14 | // 因为在重新同步 (resync) 操作中 Reflector 需要知道当前的资源状态,
15 | // 另外在计算变更 (Delta) 时,也需要对比当前的资源状态。
16 | // 这个 KnownObjects 对队列,以及对 Reflector 都是只读的,用户需要自己维护好 store 的状态。
17 | func newQueue(store cache.Store) cache.Queue {
18 | return cache.NewDeltaFIFOWithOptions(cache.DeltaFIFOOptions{
19 | KnownObjects: store,
20 | EmitDeltaTypeReplaced: true,
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/4-informer/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/4-informer/lw.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/fields"
5 | "k8s.io/client-go/tools/cache"
6 | )
7 |
8 | // newConfigMapsListerWatcher 用于创建 tmp namespace 下 configmaps 资源的 ListerWatcher 实例
9 | func newConfigMapsListerWatcher() cache.ListerWatcher {
10 | clientset := mustClientset() // 前面有说明
11 | client := clientset.CoreV1().RESTClient() // 客户端,请求器
12 | resource := "configmaps" // GET 请求参数之一
13 | namespace := "tmp" // GET 请求参数之一
14 | selector := fields.Everything() // GET 请求参数之一
15 | lw := cache.NewListWatchFromClient(client, resource, namespace, selector)
16 | return lw
17 | }
18 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/4-informer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | corev1 "k8s.io/api/core/v1"
6 | "k8s.io/client-go/tools/cache"
7 | )
8 |
9 | func main() {
10 | fmt.Println("----- 4-informer -----")
11 |
12 | lw := newConfigMapsListerWatcher()
13 | // 第一个返回的参数是 cache.Store,这里暂时用不到所以直接丢弃
14 | _, controller := cache.NewInformer(lw, &corev1.ConfigMap{}, 0, cache.ResourceEventHandlerFuncs{
15 | AddFunc: func(obj interface{}) {
16 | configMap, ok := obj.(*corev1.ConfigMap)
17 | if !ok {
18 | return
19 | }
20 | fmt.Printf("created: %s\n", configMap.Name)
21 | },
22 | UpdateFunc: func(old, new interface{}) {
23 | configMap, ok := old.(*corev1.ConfigMap)
24 | if !ok {
25 | return
26 | }
27 | fmt.Printf("updated: %s\n", configMap.Name)
28 | },
29 | DeleteFunc: func(obj interface{}) {
30 | configMap, ok := obj.(*corev1.ConfigMap)
31 | if !ok {
32 | return
33 | }
34 | fmt.Printf("deleted: %s\n", configMap.Name)
35 | },
36 | })
37 |
38 | stopCh := make(chan struct{})
39 | defer close(stopCh)
40 |
41 | fmt.Println("Start syncing....")
42 |
43 | go controller.Run(stopCh)
44 |
45 | <-stopCh
46 | }
47 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/5-shared-informer/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/5-shared-informer/lw.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/fields"
5 | "k8s.io/client-go/tools/cache"
6 | )
7 |
8 | // newConfigMapsListerWatcher 用于创建 tmp namespace 下 configmaps 资源的 ListerWatcher 实例
9 | func newConfigMapsListerWatcher() cache.ListerWatcher {
10 | clientset := mustClientset() // 前面有说明
11 | client := clientset.CoreV1().RESTClient() // 客户端,请求器
12 | resource := "configmaps" // GET 请求参数之一
13 | namespace := "tmp" // GET 请求参数之一
14 | selector := fields.Everything() // GET 请求参数之一
15 | lw := cache.NewListWatchFromClient(client, resource, namespace, selector)
16 | return lw
17 | }
18 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/5-shared-informer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | corev1 "k8s.io/api/core/v1"
6 | "k8s.io/client-go/tools/cache"
7 | )
8 |
9 | func main() {
10 | fmt.Println("----- 5-shared-informer -----")
11 |
12 | lw := newConfigMapsListerWatcher()
13 | sharedInformer := cache.NewSharedInformer(lw, &corev1.ConfigMap{}, 0)
14 | // 添加一个处理程序
15 | sharedInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
16 | AddFunc: func(obj interface{}) {
17 | configMap, ok := obj.(*corev1.ConfigMap)
18 | if !ok {
19 | return
20 | }
21 | fmt.Printf("created, printing namespace: %s\n", configMap.Namespace)
22 | },
23 | })
24 | // 添加另一个处理程序
25 | sharedInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
26 | AddFunc: func(obj interface{}) {
27 | configMap, ok := obj.(*corev1.ConfigMap)
28 | if !ok {
29 | return
30 | }
31 | fmt.Printf("created, printing name: %s\n", configMap.Name)
32 | },
33 | })
34 |
35 | stopCh := make(chan struct{})
36 | defer close(stopCh)
37 |
38 | fmt.Println("Start syncing....")
39 |
40 | go sharedInformer.Run(stopCh)
41 |
42 | <-stopCh
43 | }
44 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/6-indexer/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/6-indexer/lw.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/fields"
5 | "k8s.io/client-go/tools/cache"
6 | )
7 |
8 | // newConfigMapsListerWatcher 用于创建 tmp namespace 下 configmaps 资源的 ListerWatcher 实例
9 | func newConfigMapsListerWatcher() cache.ListerWatcher {
10 | clientset := mustClientset() // 前面有说明
11 | client := clientset.CoreV1().RESTClient() // 客户端,请求器
12 | resource := "configmaps" // GET 请求参数之一
13 | namespace := "tmp" // GET 请求参数之一
14 | selector := fields.Everything() // GET 请求参数之一
15 | lw := cache.NewListWatchFromClient(client, resource, namespace, selector)
16 | return lw
17 | }
18 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/6-indexer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/spongeprojects/magicconch"
6 | corev1 "k8s.io/api/core/v1"
7 | "k8s.io/client-go/tools/cache"
8 | )
9 |
10 | func main() {
11 | fmt.Println("----- 6-indexer -----")
12 |
13 | lw := newConfigMapsListerWatcher()
14 | indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
15 | // 仅演示用,只关心 indexer,不处理事件,所以传一个空的 HandlerFunc,
16 | // 实际使用中一般不会这样做
17 | indexer, informer := cache.NewIndexerInformer(
18 | lw, &corev1.ConfigMap{}, 0, cache.ResourceEventHandlerFuncs{}, indexers)
19 |
20 | stopCh := make(chan struct{})
21 | defer close(stopCh)
22 |
23 | fmt.Println("Start syncing....")
24 |
25 | go informer.Run(stopCh)
26 |
27 | // 在 informer 首次同步完成后再操作
28 | if !cache.WaitForCacheSync(stopCh, informer.HasSynced) {
29 | panic("timed out waiting for caches to sync")
30 | }
31 |
32 | // 获取 cache.NamespaceIndex 索引下,索引值为 "tmp" 中的所有键
33 | keys, err := indexer.IndexKeys(cache.NamespaceIndex, "tmp")
34 | magicconch.Must(err)
35 | for _, k := range keys {
36 | fmt.Println(k)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/7-indexer-informer/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/7-indexer-informer/lw.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/fields"
5 | "k8s.io/client-go/tools/cache"
6 | )
7 |
8 | // newConfigMapsListerWatcher 用于创建 tmp namespace 下 configmaps 资源的 ListerWatcher 实例
9 | func newConfigMapsListerWatcher() cache.ListerWatcher {
10 | clientset := mustClientset() // 前面有说明
11 | client := clientset.CoreV1().RESTClient() // 客户端,请求器
12 | resource := "configmaps" // GET 请求参数之一
13 | namespace := "tmp" // GET 请求参数之一
14 | selector := fields.Everything() // GET 请求参数之一
15 | lw := cache.NewListWatchFromClient(client, resource, namespace, selector)
16 | return lw
17 | }
18 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/7-indexer-informer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/spongeprojects/magicconch"
6 | corev1 "k8s.io/api/core/v1"
7 | "k8s.io/client-go/tools/cache"
8 | "strings"
9 | )
10 |
11 | func main() {
12 | fmt.Println("----- 7-indexer-informer -----")
13 |
14 | lw := newConfigMapsListerWatcher()
15 | indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
16 | indexer, informer := cache.NewIndexerInformer(lw, &corev1.ConfigMap{}, 0, cache.ResourceEventHandlerFuncs{
17 | AddFunc: func(obj interface{}) {
18 | configMap, ok := obj.(*corev1.ConfigMap)
19 | if !ok {
20 | return
21 | }
22 | fmt.Printf("created: %s\n", configMap.Name)
23 | },
24 | }, indexers)
25 |
26 | stopCh := make(chan struct{})
27 | defer close(stopCh)
28 |
29 | fmt.Println("Start syncing....")
30 |
31 | go informer.Run(stopCh)
32 |
33 | if !cache.WaitForCacheSync(stopCh, informer.HasSynced) {
34 | panic("timed out waiting for caches to sync")
35 | }
36 |
37 | keys, err := indexer.IndexKeys(cache.NamespaceIndex, "tmp")
38 | magicconch.Must(err)
39 | for _, k := range keys {
40 | fmt.Println(k)
41 | }
42 |
43 | startProbeServer(func(message string) string {
44 | keys, err := indexer.IndexKeys(cache.NamespaceIndex, "tmp")
45 | if err != nil {
46 | return "Error: " + err.Error()
47 | }
48 | return strings.Join(keys, ", ")
49 | })
50 |
51 | <-stopCh
52 | }
53 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/7-indexer-informer/probe-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/pkg/errors"
6 | "github.com/spongeprojects/magicconch"
7 | "net"
8 | )
9 |
10 | type ProbeHandlerFunc func(string) string
11 |
12 | type ProbeServer struct {
13 | handlerFunc ProbeHandlerFunc
14 | clients map[*ProbeClient]bool
15 | registerCh chan *ProbeClient
16 | unregisterCh chan *ProbeClient
17 | }
18 |
19 | type ProbeClient struct {
20 | socket net.Conn
21 | data chan []byte
22 | }
23 |
24 | func (server *ProbeServer) start() {
25 | for {
26 | select {
27 | case client := <-server.registerCh:
28 | server.clients[client] = true
29 | case client := <-server.unregisterCh:
30 | if _, ok := server.clients[client]; ok {
31 | client.socket.Close()
32 | delete(server.clients, client)
33 | }
34 | }
35 | }
36 | }
37 |
38 | func (server *ProbeServer) receive(client *ProbeClient) {
39 | for {
40 | message := make([]byte, 4096)
41 | l, err := client.socket.Read(message)
42 | if err != nil {
43 | server.unregisterCh <- client
44 | break
45 | }
46 | _, err = client.socket.Write([]byte(server.handlerFunc(string(message[:l]))))
47 | if err != nil {
48 | server.unregisterCh <- client
49 | break
50 | }
51 | }
52 | }
53 |
54 | func startProbeServer(handlerFunc ProbeHandlerFunc) {
55 | fmt.Println("Starting probe server...")
56 |
57 | listener, err := net.Listen("tcp", ":12345")
58 | magicconch.Must(err)
59 |
60 | manager := ProbeServer{
61 | handlerFunc: handlerFunc,
62 | clients: make(map[*ProbeClient]bool),
63 | registerCh: make(chan *ProbeClient),
64 | unregisterCh: make(chan *ProbeClient),
65 | }
66 |
67 | go manager.start()
68 |
69 | for {
70 | conn, err := listener.Accept()
71 | if err != nil {
72 | fmt.Println(errors.Wrap(err, "accept connection error"))
73 | }
74 | client := &ProbeClient{socket: conn}
75 | manager.registerCh <- client
76 | go manager.receive(client)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/8-shared-index-informer/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/8-shared-index-informer/lw.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/fields"
5 | "k8s.io/client-go/tools/cache"
6 | )
7 |
8 | // newConfigMapsListerWatcher 用于创建 tmp namespace 下 configmaps 资源的 ListerWatcher 实例
9 | func newConfigMapsListerWatcher() cache.ListerWatcher {
10 | clientset := mustClientset() // 前面有说明
11 | client := clientset.CoreV1().RESTClient() // 客户端,请求器
12 | resource := "configmaps" // GET 请求参数之一
13 | namespace := "tmp" // GET 请求参数之一
14 | selector := fields.Everything() // GET 请求参数之一
15 | lw := cache.NewListWatchFromClient(client, resource, namespace, selector)
16 | return lw
17 | }
18 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/8-shared-index-informer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/spongeprojects/magicconch"
6 | corev1 "k8s.io/api/core/v1"
7 | "k8s.io/client-go/tools/cache"
8 | "strings"
9 | )
10 |
11 | func main() {
12 | fmt.Println("----- 8-shared-indexer-informer -----")
13 |
14 | lw := newConfigMapsListerWatcher()
15 | indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
16 | informer := cache.NewSharedIndexInformer(lw, &corev1.ConfigMap{}, 0, indexers)
17 | informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
18 | AddFunc: func(obj interface{}) {
19 | configMap, ok := obj.(*corev1.ConfigMap)
20 | if !ok {
21 | return
22 | }
23 | fmt.Printf("created: %s\n", configMap.Name)
24 | },
25 | })
26 |
27 | stopCh := make(chan struct{})
28 | defer close(stopCh)
29 |
30 | fmt.Println("Start syncing....")
31 |
32 | go informer.Run(stopCh)
33 |
34 | if !cache.WaitForCacheSync(stopCh, informer.HasSynced) {
35 | panic("timed out waiting for caches to sync")
36 | }
37 |
38 | keys, err := informer.GetIndexer().IndexKeys(cache.NamespaceIndex, "tmp")
39 | magicconch.Must(err)
40 | for _, k := range keys {
41 | fmt.Println(k)
42 | }
43 |
44 | startProbeServer(func(message string) string {
45 | keys, err := informer.GetIndexer().IndexKeys(cache.NamespaceIndex, "tmp")
46 | if err != nil {
47 | return "Error: " + err.Error()
48 | }
49 | return strings.Join(keys, ", ")
50 | })
51 |
52 | <-stopCh
53 | }
54 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/8-shared-index-informer/probe-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/pkg/errors"
6 | "github.com/spongeprojects/magicconch"
7 | "net"
8 | )
9 |
10 | type ProbeHandlerFunc func(string) string
11 |
12 | type ProbeServer struct {
13 | handlerFunc ProbeHandlerFunc
14 | clients map[*ProbeClient]bool
15 | registerCh chan *ProbeClient
16 | unregisterCh chan *ProbeClient
17 | }
18 |
19 | type ProbeClient struct {
20 | socket net.Conn
21 | data chan []byte
22 | }
23 |
24 | func (server *ProbeServer) start() {
25 | for {
26 | select {
27 | case client := <-server.registerCh:
28 | server.clients[client] = true
29 | case client := <-server.unregisterCh:
30 | if _, ok := server.clients[client]; ok {
31 | client.socket.Close()
32 | delete(server.clients, client)
33 | }
34 | }
35 | }
36 | }
37 |
38 | func (server *ProbeServer) receive(client *ProbeClient) {
39 | for {
40 | message := make([]byte, 4096)
41 | l, err := client.socket.Read(message)
42 | if err != nil {
43 | server.unregisterCh <- client
44 | break
45 | }
46 | _, err = client.socket.Write([]byte(server.handlerFunc(string(message[:l]))))
47 | if err != nil {
48 | server.unregisterCh <- client
49 | break
50 | }
51 | }
52 | }
53 |
54 | func startProbeServer(handlerFunc ProbeHandlerFunc) {
55 | fmt.Println("Starting probe server...")
56 |
57 | listener, err := net.Listen("tcp", ":12345")
58 | magicconch.Must(err)
59 |
60 | manager := ProbeServer{
61 | handlerFunc: handlerFunc,
62 | clients: make(map[*ProbeClient]bool),
63 | registerCh: make(chan *ProbeClient),
64 | unregisterCh: make(chan *ProbeClient),
65 | }
66 |
67 | go manager.start()
68 |
69 | for {
70 | conn, err := listener.Accept()
71 | if err != nil {
72 | fmt.Println(errors.Wrap(err, "accept connection error"))
73 | }
74 | client := &ProbeClient{socket: conn}
75 | manager.registerCh <- client
76 | go manager.receive(client)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/9-shared-informer-factory/clientset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/spongeprojects/magicconch"
5 | "k8s.io/client-go/kubernetes"
6 | "k8s.io/client-go/tools/clientcmd"
7 | "os"
8 | )
9 |
10 | func mustClientset() kubernetes.Interface {
11 | kubeconfig := os.Getenv("KUBECONFIG")
12 |
13 | config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
14 | magicconch.Must(err)
15 |
16 | clientset, err := kubernetes.NewForConfig(config)
17 | magicconch.Must(err)
18 |
19 | return clientset
20 | }
21 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/9-shared-informer-factory/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | corev1 "k8s.io/api/core/v1"
6 | "k8s.io/client-go/informers"
7 | "k8s.io/client-go/tools/cache"
8 | )
9 |
10 | func main() {
11 | fmt.Println("----- 9-shared-informer-factory -----")
12 |
13 | // mustClientset 用于创建 kubernetes.Interface 实例,
14 | // 代码在前一部分中;
15 | // 第 2 个参数是 defaultResync,是构建新 Informer 时默认的 resyncPeriod,
16 | // resyncPeriod 在前一部分中介绍过了;
17 | informerFactory := informers.NewSharedInformerFactoryWithOptions(
18 | mustClientset(), 0, informers.WithNamespace("tmp"))
19 | configMapsInformer := informerFactory.Core().V1().ConfigMaps().Informer()
20 | configMapsInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
21 | AddFunc: func(obj interface{}) {
22 | configMap, ok := obj.(*corev1.ConfigMap)
23 | if !ok {
24 | return
25 | }
26 | fmt.Printf("created: %s\n", configMap.Name)
27 | },
28 | UpdateFunc: func(oldObj, newObj interface{}) {
29 | configMap, ok := newObj.(*corev1.ConfigMap)
30 | if !ok {
31 | return
32 | }
33 | fmt.Printf("updated: %s\n", configMap.Name)
34 | },
35 | DeleteFunc: func(obj interface{}) {
36 | configMap, ok := obj.(*corev1.ConfigMap)
37 | if !ok {
38 | return
39 | }
40 | fmt.Printf("deleted: %s\n", configMap.Name)
41 | },
42 | })
43 |
44 | stopCh := make(chan struct{})
45 | defer close(stopCh)
46 |
47 | fmt.Println("Start syncing....")
48 |
49 | go informerFactory.Start(stopCh)
50 |
51 | <-stopCh
52 | }
53 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/wbsnail/articles/archive/dive-into-kubernetes-informer
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/pkg/errors v0.9.1
7 | github.com/spongeprojects/magicconch v0.0.6
8 | k8s.io/api v0.21.0
9 | k8s.io/apimachinery v0.21.0
10 | k8s.io/client-go v0.21.0
11 | k8s.io/klog/v2 v2.8.0
12 | )
13 |
--------------------------------------------------------------------------------
/archive/dive-into-kubernetes-informer/informer.drawio:
--------------------------------------------------------------------------------
1 |
点击按钮,免费获取 50000 元现金奖励:
16 | 20 | 21 | `)) 22 | 23 | func main() { 24 | r := gin.Default() 25 | r.SetHTMLTemplate(tmpl) 26 | r.GET("/", func(c *gin.Context) { 27 | c.HTML(200, "index", nil) 28 | }) 29 | err := r.Run("0.0.0.0:8081") 30 | magicconch.Must(err) 31 | } 32 | -------------------------------------------------------------------------------- /lab/csrf-attack/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/basic-controller 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.7.1 7 | github.com/go-playground/validator/v10 v10.6.0 // indirect 8 | github.com/golang/protobuf v1.5.2 // indirect 9 | github.com/json-iterator/go v1.1.11 // indirect 10 | github.com/leodido/go-urn v1.2.1 // indirect 11 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 12 | github.com/modern-go/reflect2 v1.0.1 // indirect 13 | github.com/spongeprojects/magicconch v0.0.6 14 | github.com/ugorji/go v1.2.5 // indirect 15 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect 16 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 // indirect 17 | golang.org/x/text v0.3.6 // indirect 18 | gopkg.in/yaml.v2 v2.4.0 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /lab/csrf-attack/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 5 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 6 | github.com/gin-gonic/gin v1.7.1 h1:qC89GU3p8TvKWMAVhEpmpB2CIb1hnqt2UdKZaP93mS8= 7 | github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 8 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 9 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 10 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 11 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 12 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 13 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 14 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 15 | github.com/go-playground/validator/v10 v10.6.0 h1:UGIt4xR++fD9QrBOoo/ascJfGe3AGHEB9s6COnss4Rk= 16 | github.com/go-playground/validator/v10 v10.6.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk= 17 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 18 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 19 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 20 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 21 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 22 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 23 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 24 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 25 | github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= 26 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 27 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 28 | github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= 29 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 30 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 31 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 32 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 33 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 34 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 35 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 36 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 37 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 38 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 39 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 40 | github.com/spongeprojects/magicconch v0.0.6 h1:mSfokxxWC9hglSCM5FUrhdBg7tUFGbEePGWEo+3Ol8c= 41 | github.com/spongeprojects/magicconch v0.0.6/go.mod h1:Ad8z6fYdCtlbl9gKgQ4p+W4NgIKyMyruipD0/H7S3n8= 42 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 43 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 44 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 45 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 46 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 47 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 48 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 49 | github.com/ugorji/go v1.2.5 h1:NozRHfUeEta89taVkyfsDVSy2f7v89Frft4pjnWuGuc= 50 | github.com/ugorji/go v1.2.5/go.mod h1:gat2tIT8KJG8TVI8yv77nEO/KYT6dV7JE1gfUa8Xuls= 51 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 52 | github.com/ugorji/go/codec v1.2.5 h1:8WobZKAk18Msm2CothY2jnztY56YVY8kF1oQrj21iis= 53 | github.com/ugorji/go/codec v1.2.5/go.mod h1:QPxoTbPKSEAlAHPYt02++xp/en9B/wUdwFCz+hj5caA= 54 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 55 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 56 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o= 57 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 58 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 59 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 60 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 61 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 62 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 63 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 64 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 h1:5PbJGn5Sp3GEUjJ61aYbUP6RIo3Z3r2E4Tv9y2z8UHo= 65 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 66 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 67 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 68 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 69 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 70 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 71 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 72 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 73 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 74 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 75 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 76 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 77 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 78 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 79 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 80 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 81 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 82 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 83 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 84 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 85 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 86 | -------------------------------------------------------------------------------- /lab/csrf-attack/server-protected/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/spongeprojects/magicconch" 6 | "html/template" 7 | ) 8 | 9 | var tmpl = template.Must(template.New("index").Parse(` 10 | 11 | 12 |账户余额:
16 |[退出] 你好, {{.Username}}
26 | 31 | {{else}} 32 |登录:
33 | 37 | {{end}} 38 | 39 | `)) 40 | 41 | var users = make(map[string]int) 42 | var sessions = make(map[string]string) 43 | var csrfSessions = make(map[string]string) 44 | 45 | func main() { 46 | r := gin.Default() 47 | r.SetHTMLTemplate(tmpl) 48 | r.GET("/", func(c *gin.Context) { 49 | // 获取会话 ID 50 | sessionID, _ := c.Cookie("sessionID") 51 | // 根据会话 ID 查找用户 52 | username, loggedIn := sessions[sessionID] 53 | csrfToken := magicconch.StringRand(32) 54 | csrfSessions[sessionID] = csrfToken 55 | 56 | c.HTML(200, "index", gin.H{ 57 | "LoggedIn": loggedIn, 58 | "Username": username, 59 | "Users": users, 60 | "CSRFToken": csrfToken, 61 | }) 62 | }) 63 | r.POST("/login", func(c *gin.Context) { 64 | username := c.PostForm("username") 65 | users[username] = 1000 66 | // 生成并保存新会话 67 | sessionID := magicconch.StringRand(32) 68 | sessions[sessionID] = username 69 | // 保存会话 ID 到客户端 70 | c.SetCookie("sessionID", sessionID, 3600, "/", "", false, false) 71 | // 登录后回到首页(不能直接把 POST 请求重定向到首页) 72 | c.Header("Content-Type", "text/html") 73 | c.String(200, "") 74 | }) 75 | r.POST("/transfer", func(c *gin.Context) { 76 | // 获取会话 ID 77 | sessionID, _ := c.Cookie("sessionID") 78 | // 根据会话 ID 查找用户 79 | username, loggedIn := sessions[sessionID] 80 | if !loggedIn { 81 | c.String(403, "你没有登录") 82 | return 83 | } 84 | amount := magicconch.StringToInt(c.PostForm("amount")) 85 | csrfToken := c.PostForm("csrf_token") 86 | if csrfSessions[sessionID] != csrfToken { 87 | c.String(403, "CSRF 攻击,抓到你啦!(如果你不是恶意用户,请刷新页面重试)") 88 | return 89 | } 90 | users[username] -= amount 91 | // 转账完成后回到首页(不能直接把 POST 请求重定向到首页) 92 | c.Header("Content-Type", "text/html") 93 | c.String(200, "") 94 | }) 95 | r.GET("/logout", func(c *gin.Context) { 96 | // 清除会话 97 | c.SetCookie("sessionID", "", 0, "/", "", false, false) 98 | // 退出登录后回到首页 99 | c.Redirect(307, "/") 100 | }) 101 | err := r.Run("0.0.0.0:8080") 102 | magicconch.Must(err) 103 | } 104 | -------------------------------------------------------------------------------- /lab/csrf-attack/server-volunable/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/spongeprojects/magicconch" 6 | "html/template" 7 | ) 8 | 9 | var tmpl = template.Must(template.New("index").Parse(` 10 | 11 | 12 |账户余额:
16 |[退出] 你好, {{.Username}}
26 | 30 | {{else}} 31 |登录:
32 | 36 | {{end}} 37 | 38 | `)) 39 | 40 | var users = make(map[string]int) 41 | var sessions = make(map[string]string) 42 | 43 | func main() { 44 | r := gin.Default() 45 | r.SetHTMLTemplate(tmpl) 46 | r.GET("/", func(c *gin.Context) { 47 | // 获取会话 ID 48 | sessionID, _ := c.Cookie("sessionID") 49 | // 根据会话 ID 查找用户 50 | username, loggedIn := sessions[sessionID] 51 | 52 | c.HTML(200, "index", gin.H{ 53 | "LoggedIn": loggedIn, 54 | "Username": username, 55 | "Users": users, 56 | }) 57 | }) 58 | r.POST("/login", func(c *gin.Context) { 59 | username := c.PostForm("username") 60 | users[username] = 1000 61 | // 生成并保存新会话 62 | sessionID := magicconch.StringRand(32) 63 | sessions[sessionID] = username 64 | // 保存会话 ID 到客户端 65 | c.SetCookie("sessionID", sessionID, 3600, "/", "", false, false) 66 | // 登录后回到首页(不能直接把 POST 请求重定向到首页) 67 | c.Header("Content-Type", "text/html") 68 | c.String(200, "") 69 | }) 70 | r.POST("/transfer", func(c *gin.Context) { 71 | // 获取会话 ID 72 | sessionID, _ := c.Cookie("sessionID") 73 | // 根据会话 ID 查找用户 74 | username, loggedIn := sessions[sessionID] 75 | if !loggedIn { 76 | c.String(403, "你没有登录") 77 | return 78 | } 79 | amount := magicconch.StringToInt(c.PostForm("amount")) 80 | users[username] -= amount 81 | // 转账完成后回到首页(不能直接把 POST 请求重定向到首页) 82 | c.Header("Content-Type", "text/html") 83 | c.String(200, "") 84 | }) 85 | r.GET("/logout", func(c *gin.Context) { 86 | // 清除会话 87 | c.SetCookie("sessionID", "", 0, "/", "", false, false) 88 | // 退出登录后回到首页 89 | c.Redirect(307, "/") 90 | }) 91 | err := r.Run("0.0.0.0:8080") 92 | magicconch.Must(err) 93 | } 94 | -------------------------------------------------------------------------------- /lab/shadow-string/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/basic-controller 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /lab/shadow-string/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junchaw/articles/0fb09b5689e2cbcdfeb88790eaafead50d0fac89/lab/shadow-string/go.sum -------------------------------------------------------------------------------- /lab/shadow-string/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | a := make([]byte, 16) 10 | 11 | r := strings.NewReader("test") 12 | _, _ = r.Read(a) 13 | 14 | b := "test" 15 | 16 | fmt.Println(string(a), b) 17 | fmt.Println(string(a) == b) 18 | fmt.Println(len(string(a)), len(b)) 19 | fmt.Println(a, []byte(b)) 20 | } 21 | -------------------------------------------------------------------------------- /lab/unix-socket-broadcast/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "github.com/pkg/errors" 7 | "github.com/spongeprojects/magicconch" 8 | "net" 9 | "os" 10 | "strings" 11 | ) 12 | 13 | type Client struct { 14 | socket net.Conn 15 | } 16 | 17 | func (client *Client) receive() { 18 | defer func(socket net.Conn) { 19 | err := socket.Close() 20 | if err != nil { 21 | fmt.Println(errors.Wrap(err, "close socket error")) 22 | } 23 | }(client.socket) 24 | 25 | for { 26 | message := make([]byte, 4096) 27 | length, err := client.socket.Read(message) 28 | if err != nil { 29 | break 30 | } 31 | if length > 0 { 32 | fmt.Println("[RECEIVED]: " + string(message)) 33 | } 34 | } 35 | } 36 | 37 | func main() { 38 | fmt.Println("Starting client...") 39 | 40 | conn, err := net.Dial("tcp", "localhost:12345") 41 | magicconch.Must(err) 42 | 43 | client := &Client{socket: conn} 44 | 45 | go client.receive() 46 | 47 | fmt.Println("[WAITING]") 48 | for { 49 | reader := bufio.NewReader(os.Stdin) 50 | message, _ := reader.ReadString('\n') 51 | message = strings.Trim(message, "\n") 52 | fmt.Println("[SENDING]: " + message) 53 | _, err := conn.Write([]byte(message)) 54 | if err != nil { 55 | fmt.Println(errors.Wrap(err, "send message error")) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lab/unix-socket-broadcast/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/basic-controller 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/pkg/errors v0.9.1 7 | github.com/spongeprojects/magicconch v0.0.6 8 | ) 9 | -------------------------------------------------------------------------------- /lab/unix-socket-broadcast/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 4 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/spongeprojects/magicconch v0.0.6 h1:mSfokxxWC9hglSCM5FUrhdBg7tUFGbEePGWEo+3Ol8c= 8 | github.com/spongeprojects/magicconch v0.0.6/go.mod h1:Ad8z6fYdCtlbl9gKgQ4p+W4NgIKyMyruipD0/H7S3n8= 9 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 11 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | -------------------------------------------------------------------------------- /lab/unix-socket-broadcast/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pkg/errors" 6 | "github.com/spongeprojects/magicconch" 7 | "net" 8 | ) 9 | 10 | type ClientManager struct { 11 | clients map[*Client]bool 12 | broadcastCh chan []byte 13 | registerCh chan *Client 14 | unregisterCh chan *Client 15 | } 16 | 17 | type Client struct { 18 | socket net.Conn 19 | data chan []byte 20 | } 21 | 22 | func (manager *ClientManager) start() { 23 | for { 24 | select { 25 | case client := <-manager.registerCh: 26 | manager.clients[client] = true 27 | fmt.Println("[REGISTERED]: Client registered!") 28 | case client := <-manager.unregisterCh: 29 | if _, ok := manager.clients[client]; ok { 30 | close(client.data) 31 | delete(manager.clients, client) 32 | fmt.Println("[UNREGISTERED]: Client unregistered!") 33 | } 34 | case message := <-manager.broadcastCh: 35 | fmt.Println("[BROADCASTING]: " + string(message)) 36 | for client := range manager.clients { 37 | select { 38 | case client.data <- message: 39 | default: 40 | close(client.data) 41 | delete(manager.clients, client) 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | func (manager *ClientManager) receive(client *Client) { 49 | for { 50 | message := make([]byte, 4096) 51 | length, err := client.socket.Read(message) 52 | if err != nil { 53 | manager.unregisterCh <- client 54 | client.socket.Close() 55 | break 56 | } 57 | if length > 0 { 58 | fmt.Println("[RECEIVED]: " + string(message)) 59 | manager.broadcastCh <- message 60 | } 61 | } 62 | } 63 | 64 | func (manager *ClientManager) send(client *Client) { 65 | defer client.socket.Close() 66 | for { 67 | select { 68 | case message, ok := <-client.data: 69 | if !ok { 70 | return 71 | } 72 | client.socket.Write(message) 73 | } 74 | } 75 | } 76 | 77 | func main() { 78 | fmt.Println("Starting server...") 79 | 80 | listener, err := net.Listen("tcp", ":12345") 81 | magicconch.Must(err) 82 | 83 | manager := ClientManager{ 84 | clients: make(map[*Client]bool), 85 | broadcastCh: make(chan []byte), 86 | registerCh: make(chan *Client), 87 | unregisterCh: make(chan *Client), 88 | } 89 | 90 | go manager.start() 91 | 92 | fmt.Println("[WAITING]") 93 | for { 94 | conn, err := listener.Accept() 95 | if err != nil { 96 | fmt.Println(errors.Wrap(err, "accept connection error")) 97 | } 98 | client := &Client{socket: conn, data: make(chan []byte)} 99 | manager.registerCh <- client 100 | go manager.receive(client) 101 | go manager.send(client) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /lab/unix-socket-echo/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "github.com/pkg/errors" 7 | "github.com/spongeprojects/magicconch" 8 | "net" 9 | "os" 10 | "strings" 11 | ) 12 | 13 | type Client struct { 14 | socket net.Conn 15 | } 16 | 17 | func (client *Client) receive() { 18 | defer func(socket net.Conn) { 19 | err := socket.Close() 20 | if err != nil { 21 | fmt.Println(errors.Wrap(err, "close socket error")) 22 | } 23 | }(client.socket) 24 | 25 | for { 26 | message := make([]byte, 4096) 27 | length, err := client.socket.Read(message) 28 | if err != nil { 29 | break 30 | } 31 | if length > 0 { 32 | fmt.Println("[RECEIVED]: " + string(message)) 33 | } 34 | } 35 | } 36 | 37 | func main() { 38 | fmt.Println("Starting client...") 39 | 40 | conn, err := net.Dial("tcp", "localhost:12345") 41 | magicconch.Must(err) 42 | 43 | client := &Client{socket: conn} 44 | 45 | go client.receive() 46 | 47 | fmt.Println("[WAITING]") 48 | for { 49 | reader := bufio.NewReader(os.Stdin) 50 | message, _ := reader.ReadString('\n') 51 | message = strings.Trim(message, "\n") 52 | fmt.Println("[SENDING]: " + message) 53 | _, err := conn.Write([]byte(message)) 54 | if err != nil { 55 | fmt.Println(errors.Wrap(err, "send message error")) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lab/unix-socket-echo/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/basic-controller 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/pkg/errors v0.9.1 7 | github.com/spongeprojects/magicconch v0.0.6 8 | ) 9 | -------------------------------------------------------------------------------- /lab/unix-socket-echo/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 4 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/spongeprojects/magicconch v0.0.6 h1:mSfokxxWC9hglSCM5FUrhdBg7tUFGbEePGWEo+3Ol8c= 8 | github.com/spongeprojects/magicconch v0.0.6/go.mod h1:Ad8z6fYdCtlbl9gKgQ4p+W4NgIKyMyruipD0/H7S3n8= 9 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 11 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | -------------------------------------------------------------------------------- /lab/unix-socket-echo/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pkg/errors" 6 | "github.com/spongeprojects/magicconch" 7 | "net" 8 | ) 9 | 10 | type ClientManager struct { 11 | clients map[*Client]bool 12 | registerCh chan *Client 13 | unregisterCh chan *Client 14 | } 15 | 16 | type Client struct { 17 | socket net.Conn 18 | data chan []byte 19 | } 20 | 21 | func (manager *ClientManager) start() { 22 | for { 23 | select { 24 | case client := <-manager.registerCh: 25 | manager.clients[client] = true 26 | fmt.Println("[REGISTERED]: Client registered!") 27 | case client := <-manager.unregisterCh: 28 | if _, ok := manager.clients[client]; ok { 29 | close(client.data) 30 | delete(manager.clients, client) 31 | fmt.Println("[UNREGISTERED]: Client unregistered!") 32 | } 33 | } 34 | } 35 | } 36 | 37 | func (manager *ClientManager) receive(client *Client) { 38 | for { 39 | message := make([]byte, 4096) 40 | _, err := client.socket.Read(message) 41 | if err != nil { 42 | manager.unregisterCh <- client 43 | client.socket.Close() 44 | break 45 | } 46 | select { 47 | case client.data <- message: 48 | default: 49 | close(client.data) 50 | delete(manager.clients, client) 51 | } 52 | } 53 | } 54 | 55 | func (manager *ClientManager) send(client *Client) { 56 | defer client.socket.Close() 57 | for { 58 | select { 59 | case message, ok := <-client.data: 60 | if !ok { 61 | return 62 | } 63 | client.socket.Write(message) 64 | } 65 | } 66 | } 67 | 68 | func main() { 69 | fmt.Println("Starting server...") 70 | 71 | listener, err := net.Listen("tcp", ":12345") 72 | magicconch.Must(err) 73 | 74 | manager := ClientManager{ 75 | clients: make(map[*Client]bool), 76 | registerCh: make(chan *Client), 77 | unregisterCh: make(chan *Client), 78 | } 79 | 80 | go manager.start() 81 | 82 | fmt.Println("[WAITING]") 83 | for { 84 | conn, err := listener.Accept() 85 | if err != nil { 86 | fmt.Println(errors.Wrap(err, "accept connection error")) 87 | } 88 | client := &Client{socket: conn, data: make(chan []byte)} 89 | manager.registerCh <- client 90 | go manager.receive(client) 91 | go manager.send(client) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lab/upgrade-plan/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math/rand" 7 | "os" 8 | "strconv" 9 | "time" 10 | ) 11 | 12 | var debug = os.Getenv("DEBUG") != "" 13 | var counter = 0 14 | 15 | type DisruptionBudget struct { 16 | AppName string 17 | DisruptionAllowed int 18 | } 19 | 20 | type Node struct { 21 | NodeName string 22 | } 23 | 24 | // Application represents an instance, like a Pod 25 | type Application struct { 26 | AppName string 27 | NodeName string 28 | } 29 | 30 | type Calculator struct { 31 | pods map[string]map[string]bool 32 | memo map[[16]byte][]string 33 | } 34 | 35 | // calculateStep finds nodes that can be upgraded at once 36 | func (c *Calculator) calculateStep(nodes []string, budgets map[string]int) (steps []string) { 37 | if debug { 38 | counter++ 39 | log.Println(counter, nodes, budgets) 40 | } 41 | 42 | budgetsLeft := budgets 43 | for _, node := range nodes { 44 | canUpgrade := true 45 | appsOnNode := c.pods[node] 46 | budgetsIfUpgrade := make(map[string]int) 47 | for app := range budgetsLeft { 48 | if appsOnNode[app] { 49 | budgetsIfUpgrade[app] = budgetsLeft[app] - 1 50 | if budgetsIfUpgrade[app] < 0 { 51 | canUpgrade = false 52 | break 53 | } 54 | } else { 55 | budgetsIfUpgrade[app] = budgetsLeft[app] 56 | } 57 | } 58 | 59 | if canUpgrade { 60 | budgetsLeft = budgetsIfUpgrade 61 | steps = append(steps, node) 62 | } 63 | } 64 | return steps 65 | } 66 | 67 | // calculate generates an upgrade plan 68 | func (c *Calculator) calculate(nodes []string, budgets map[string]int) [][]string { 69 | log.Println("calculating...") 70 | var plan [][]string 71 | for len(nodes) > 0 { 72 | var nodesLeft []string 73 | step := c.calculateStep(nodes, budgets) 74 | log.Printf("step calculated: %v", step) 75 | for _, node := range nodes { 76 | if !stringInSlice(node, step) { 77 | nodesLeft = append(nodesLeft, node) 78 | } 79 | } 80 | plan = append(plan, step) 81 | if len(nodes) == len(nodesLeft) { 82 | log.Fatalf("no nodes can be upgraded: %v", nodes) 83 | } 84 | nodes = nodesLeft 85 | } 86 | return plan 87 | } 88 | 89 | // GeneratePlan generates an upgrade plan 90 | func (c *Calculator) GeneratePlan(nodes []Node, pods []Application, budgets []DisruptionBudget) [][]string { 91 | log.Println("preparing...") 92 | var nodeNames []string 93 | for _, node := range nodes { 94 | nodeNames = append(nodeNames, node.NodeName) 95 | } 96 | podsOnNode := make(map[string]map[string]bool) 97 | for _, pod := range pods { 98 | if podsOnNode[pod.NodeName] == nil { 99 | podsOnNode[pod.NodeName] = make(map[string]bool) 100 | } 101 | podsOnNode[pod.NodeName][pod.AppName] = true 102 | } 103 | budgetMap := make(map[string]int) 104 | for _, budget := range budgets { 105 | budgetMap[budget.AppName] = budget.DisruptionAllowed 106 | } 107 | c.pods = podsOnNode 108 | return c.calculate(nodeNames, budgetMap) 109 | } 110 | 111 | func stringInSlice(str string, slice []string) bool { 112 | for _, s := range slice { 113 | if s == str { 114 | return true 115 | } 116 | } 117 | return false 118 | } 119 | 120 | type Testcase struct { 121 | Nodes []Node 122 | Pods []Application 123 | Budgets []DisruptionBudget 124 | } 125 | 126 | var testcases = []Testcase{ 127 | { 128 | Nodes: []Node{ 129 | {NodeName: "n1"}, 130 | {NodeName: "n2"}, 131 | {NodeName: "n3"}, 132 | }, 133 | Pods: []Application{ 134 | {AppName: "app1", NodeName: "n1"}, 135 | {AppName: "app1", NodeName: "n2"}, 136 | {AppName: "app2", NodeName: "n1"}, 137 | {AppName: "app2", NodeName: "n2"}, 138 | {AppName: "app3", NodeName: "n2"}, 139 | {AppName: "app3", NodeName: "n3"}, 140 | }, 141 | Budgets: []DisruptionBudget{ 142 | {AppName: "app1", DisruptionAllowed: 1}, 143 | {AppName: "app2", DisruptionAllowed: 1}, 144 | {AppName: "app3", DisruptionAllowed: 1}, 145 | }, 146 | }, 147 | { 148 | Nodes: []Node{ 149 | {NodeName: "n1"}, 150 | {NodeName: "n2"}, 151 | {NodeName: "n3"}, 152 | {NodeName: "n4"}, 153 | {NodeName: "n5"}, 154 | {NodeName: "n6"}, 155 | {NodeName: "n7"}, 156 | {NodeName: "n8"}, 157 | {NodeName: "n9"}, 158 | {NodeName: "n10"}, 159 | }, 160 | Pods: []Application{ 161 | {NodeName: "n1", AppName: "app1"}, 162 | {NodeName: "n1", AppName: "app3"}, 163 | {NodeName: "n1", AppName: "app4"}, 164 | {NodeName: "n2", AppName: "app1"}, 165 | {NodeName: "n2", AppName: "app2"}, 166 | {NodeName: "n3", AppName: "app1"}, 167 | {NodeName: "n3", AppName: "app2"}, 168 | {NodeName: "n3", AppName: "app3"}, 169 | {NodeName: "n3", AppName: "app6"}, 170 | {NodeName: "n4", AppName: "app1"}, 171 | {NodeName: "n4", AppName: "app2"}, 172 | {NodeName: "n4", AppName: "app3"}, 173 | {NodeName: "n4", AppName: "app4"}, 174 | {NodeName: "n5", AppName: "app1"}, 175 | {NodeName: "n5", AppName: "app2"}, 176 | {NodeName: "n5", AppName: "app3"}, 177 | {NodeName: "n6", AppName: "app1"}, 178 | {NodeName: "n6", AppName: "app2"}, 179 | {NodeName: "n6", AppName: "app3"}, 180 | {NodeName: "n6", AppName: "app4"}, 181 | {NodeName: "n6", AppName: "app6"}, 182 | {NodeName: "n7", AppName: "app1"}, 183 | {NodeName: "n7", AppName: "app3"}, 184 | {NodeName: "n8", AppName: "app1"}, 185 | {NodeName: "n8", AppName: "app2"}, 186 | {NodeName: "n8", AppName: "app3"}, 187 | {NodeName: "n8", AppName: "app5"}, 188 | {NodeName: "n9", AppName: "app1"}, 189 | {NodeName: "n9", AppName: "app2"}, 190 | {NodeName: "n9", AppName: "app3"}, 191 | {NodeName: "n9", AppName: "app5"}, 192 | {NodeName: "n9", AppName: "app6"}, 193 | {NodeName: "n10", AppName: "app1"}, 194 | {NodeName: "n10", AppName: "app2"}, 195 | {NodeName: "n10", AppName: "app5"}, 196 | {NodeName: "n10", AppName: "app6"}, 197 | }, 198 | Budgets: []DisruptionBudget{ 199 | {AppName: "app1", DisruptionAllowed: 4}, 200 | {AppName: "app2", DisruptionAllowed: 8}, 201 | {AppName: "app3", DisruptionAllowed: 2}, 202 | {AppName: "app4", DisruptionAllowed: 2}, 203 | {AppName: "app5", DisruptionAllowed: 2}, 204 | {AppName: "app6", DisruptionAllowed: 2}, 205 | }, 206 | }, 207 | } 208 | 209 | // main 210 | // 211 | // To be considered: 212 | // - pods may be changed (scaled, rescheduled) during operation; 213 | // - apps may have more complex disruption restrictions; 214 | func main() { 215 | rand.Seed(time.Now().Unix()) 216 | 217 | if len(os.Args) < 3 { 218 | fmt.Println("usage: go run . [action]\n" + 219 | "\n" + 220 | "go run . testcase 0 # test specific testcase, index: 0\n" + 221 | "go run . random 10 5 # test random generated testcase, 10 nodes, 5 apps") 222 | return 223 | } 224 | 225 | action := os.Args[1] 226 | 227 | var testcase Testcase 228 | switch action { 229 | case "testcase": 230 | // test specific testcase 231 | if len(os.Args) < 3 { 232 | fmt.Println("arg missing") 233 | return 234 | } 235 | 236 | n, _ := strconv.Atoi(os.Args[2]) 237 | 238 | if n < 0 || n > len(testcases)-1 { 239 | fmt.Printf("undefined testcase: %s\n", os.Args[2]) 240 | return 241 | } 242 | testcase = testcases[n] 243 | case "random": 244 | // test random generated testcase 245 | if len(os.Args) < 4 { 246 | fmt.Println("arg missing") 247 | return 248 | } 249 | 250 | nNodes, _ := strconv.Atoi(os.Args[2]) 251 | nApps, _ := strconv.Atoi(os.Args[3]) 252 | 253 | fmt.Println("generating random testcase...") 254 | var nodes []Node 255 | var pods []Application 256 | var budgets []DisruptionBudget 257 | for i := 0; i < nNodes; i++ { 258 | nodes = append(nodes, Node{NodeName: fmt.Sprintf("n%d", i+1)}) 259 | } 260 | for i := 0; i < nApps; i++ { 261 | var expectNumberOfPods int 262 | if nNodes < 200 { 263 | expectNumberOfPods = rand.Intn(nNodes) // like 2/3, 3/5 264 | } else { 265 | expectNumberOfPods = rand.Intn(200) // like 60/200, 80/5000, not too many 266 | } 267 | actualNumberOfPods := 0 268 | for j := 0; j < nNodes; j++ { 269 | if rand.Intn(nNodes) < expectNumberOfPods { 270 | pods = append(pods, Application{ 271 | AppName: fmt.Sprintf("app%d", i+1), 272 | NodeName: fmt.Sprintf("n%d", j+1), 273 | }) 274 | actualNumberOfPods += 1 275 | } 276 | } 277 | if actualNumberOfPods > 0 { 278 | var disruptionAllowed int 279 | if actualNumberOfPods < 100 { 280 | disruptionAllowed = rand.Intn(actualNumberOfPods) + 1 281 | } else { 282 | disruptionAllowed = rand.Intn(100) + 1 283 | } 284 | budgets = append(budgets, DisruptionBudget{ 285 | AppName: fmt.Sprintf("app%d", i+1), DisruptionAllowed: disruptionAllowed}) 286 | } 287 | } 288 | testcase = Testcase{ 289 | Nodes: nodes, 290 | Pods: pods, 291 | Budgets: budgets, 292 | } 293 | default: 294 | fmt.Printf("unknown action: %s\n", action) 295 | return 296 | } 297 | 298 | calculator := Calculator{ 299 | memo: make(map[[16]byte][]string), 300 | } 301 | 302 | fmt.Printf("\nnodes:\n") 303 | for _, node := range testcase.Nodes { 304 | var podsOnNode []string 305 | for _, pod := range testcase.Pods { 306 | if pod.NodeName == node.NodeName { 307 | podsOnNode = append(podsOnNode, pod.AppName) 308 | } 309 | } 310 | fmt.Printf(" %s: %v\n", node.NodeName, podsOnNode) 311 | } 312 | fmt.Println("budgets:") 313 | for _, budget := range testcase.Budgets { 314 | fmt.Printf(" %s: %d\n", budget.AppName, budget.DisruptionAllowed) 315 | } 316 | fmt.Println() 317 | 318 | start := time.Now() 319 | _ = calculator.GeneratePlan(testcase.Nodes, testcase.Pods, testcase.Budgets) 320 | end := time.Now() 321 | 322 | fmt.Printf("\ntime spent: %v\n", end.Sub(start)) 323 | } 324 | -------------------------------------------------------------------------------- /lab/xss-attack/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wbsnail/articles/archive/dive-into-kubernetes-informer/basic-controller 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.7.1 7 | github.com/go-playground/validator/v10 v10.6.0 // indirect 8 | github.com/golang/protobuf v1.5.2 // indirect 9 | github.com/json-iterator/go v1.1.11 // indirect 10 | github.com/leodido/go-urn v1.2.1 // indirect 11 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 12 | github.com/modern-go/reflect2 v1.0.1 // indirect 13 | github.com/spongeprojects/magicconch v0.0.6 14 | github.com/ugorji/go v1.2.5 // indirect 15 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect 16 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 // indirect 17 | golang.org/x/text v0.3.6 // indirect 18 | gopkg.in/yaml.v2 v2.4.0 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /lab/xss-attack/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 5 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 6 | github.com/gin-gonic/gin v1.7.1 h1:qC89GU3p8TvKWMAVhEpmpB2CIb1hnqt2UdKZaP93mS8= 7 | github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 8 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 9 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 10 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 11 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 12 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 13 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 14 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 15 | github.com/go-playground/validator/v10 v10.6.0 h1:UGIt4xR++fD9QrBOoo/ascJfGe3AGHEB9s6COnss4Rk= 16 | github.com/go-playground/validator/v10 v10.6.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk= 17 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 18 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 19 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 20 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 21 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 22 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 23 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 24 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 25 | github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= 26 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 27 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 28 | github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= 29 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 30 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 31 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 32 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 33 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 34 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 35 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 36 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 37 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 38 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 39 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 40 | github.com/spongeprojects/magicconch v0.0.6 h1:mSfokxxWC9hglSCM5FUrhdBg7tUFGbEePGWEo+3Ol8c= 41 | github.com/spongeprojects/magicconch v0.0.6/go.mod h1:Ad8z6fYdCtlbl9gKgQ4p+W4NgIKyMyruipD0/H7S3n8= 42 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 43 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 44 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 45 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 46 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 47 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 48 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 49 | github.com/ugorji/go v1.2.5 h1:NozRHfUeEta89taVkyfsDVSy2f7v89Frft4pjnWuGuc= 50 | github.com/ugorji/go v1.2.5/go.mod h1:gat2tIT8KJG8TVI8yv77nEO/KYT6dV7JE1gfUa8Xuls= 51 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 52 | github.com/ugorji/go/codec v1.2.5 h1:8WobZKAk18Msm2CothY2jnztY56YVY8kF1oQrj21iis= 53 | github.com/ugorji/go/codec v1.2.5/go.mod h1:QPxoTbPKSEAlAHPYt02++xp/en9B/wUdwFCz+hj5caA= 54 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 55 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 56 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o= 57 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 58 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 59 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 60 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 61 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 62 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 63 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 64 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 h1:5PbJGn5Sp3GEUjJ61aYbUP6RIo3Z3r2E4Tv9y2z8UHo= 65 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 66 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 67 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 68 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 69 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 70 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 71 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 72 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 73 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 74 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 75 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 76 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 77 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 78 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 79 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 80 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 81 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 82 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 83 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 84 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 85 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 86 | -------------------------------------------------------------------------------- /lab/xss-attack/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/spongeprojects/magicconch" 6 | "html/template" 7 | ) 8 | 9 | var tmpl = template.Must(template.New("index").Parse(` 10 | 11 | 12 |注册用户列表:
16 |[退出] 你好, {{.Username}}
26 | {{else}} 27 |登录:
28 | 32 | {{end}} 33 | 34 | `)) 35 | 36 | var users = make([]string, 0) 37 | var sessions = make(map[string]string) 38 | 39 | func main() { 40 | r := gin.Default() 41 | r.SetHTMLTemplate(tmpl) 42 | r.GET("/", func(c *gin.Context) { 43 | // 获取会话 ID 44 | sessionID, _ := c.Cookie("sessionID") 45 | // 根据会话 ID 查找用户 46 | username, loggedIn := sessions[sessionID] 47 | 48 | // 为了演示 XSS 攻击我们需要特地将 username 包装为 template.HTML, 49 | // 因为 html/template 包默认会帮我们对特殊字符进行转义 50 | var usersHTML []template.HTML 51 | for _, user := range users { 52 | usersHTML = append(usersHTML, template.HTML(user)) 53 | } 54 | c.HTML(200, "index", gin.H{ 55 | "LoggedIn": loggedIn, 56 | "Username": username, 57 | "Users": usersHTML, 58 | }) 59 | }) 60 | r.POST("/login", func(c *gin.Context) { 61 | username := c.PostForm("username") 62 | if !magicconch.StringInSlice(username, users) { 63 | users = append(users, username) 64 | } 65 | // 生成并保存新会话 66 | sessionID := magicconch.StringRand(32) 67 | sessions[sessionID] = username 68 | // 保存会话 ID 到客户端 69 | c.SetCookie("sessionID", sessionID, 3600, "/", "", false, false) 70 | // 登录后回到首页(不能直接把 POST 请求重定向到首页) 71 | c.Header("Content-Type", "text/html") 72 | c.String(200, "") 73 | }) 74 | r.GET("/logout", func(c *gin.Context) { 75 | // 清除会话 76 | c.SetCookie("sessionID", "", 0, "/", "", false, false) 77 | // 退出登录后回到首页 78 | c.Redirect(307, "/") 79 | }) 80 | err := r.Run("0.0.0.0:8080") 81 | magicconch.Must(err) 82 | } 83 | --------------------------------------------------------------------------------