1 package cmd
2
3 import (
4 "bytes"
5 "fmt"
6 "io"
7 "strings"
8
9 "github.com/spf13/cobra"
10 cobradoc "github.com/spf13/cobra/doc"
11 "sigs.k8s.io/yaml"
12
13 "github.com/linkerd/linkerd2/pkg/k8s"
14 )
15
16 type references struct {
17 CLIReference []cmdDoc
18 AnnotationsReference []annotationDoc
19 }
20
21 type cmdOption struct {
22 Name string
23 Shorthand string
24 DefaultValue string
25 Usage string
26 }
27
28 type cmdDoc struct {
29 Name string
30 Synopsis string
31 Description string
32 Options []cmdOption
33 InheritedOptions []cmdOption
34 Example string
35 SeeAlso []string
36 }
37
38 type annotationDoc struct {
39 Name string
40 Description string
41 }
42
43 func newCmdDoc() *cobra.Command {
44 cmd := &cobra.Command{
45 Use: "doc",
46 Hidden: true,
47 Short: "Generate YAML documentation for the Linkerd CLI & Proxy annotations",
48 Args: cobra.NoArgs,
49 RunE: func(cmd *cobra.Command, args []string) error {
50 cmdList, err := generateCLIDocs(RootCmd)
51 if err != nil {
52 return err
53 }
54
55 annotations := generateAnnotationsDocs()
56
57 ref := references{
58 CLIReference: cmdList,
59 AnnotationsReference: annotations,
60 }
61 out, err := yaml.Marshal(ref)
62 if err != nil {
63 return err
64 }
65
66 warn := "# Automatically generated by the linkerd doc command, do not manually edit"
67 fmt.Printf("%s\n\n%s\n", warn, out)
68
69 return nil
70 },
71 }
72
73 return cmd
74 }
75
76
77
78 func generateCLIDocs(cmd *cobra.Command) ([]cmdDoc, error) {
79 var cmdList []cmdDoc
80
81 for _, c := range cmd.Commands() {
82 if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
83 continue
84 }
85
86 subList, err := generateCLIDocs(c)
87 if err != nil {
88 return nil, err
89 }
90
91 cmdList = append(cmdList, subList...)
92 }
93
94 var buf bytes.Buffer
95
96 if err := cobradoc.GenYaml(cmd, io.Writer(&buf)); err != nil {
97 return nil, err
98 }
99
100 var doc cmdDoc
101 if err := yaml.Unmarshal(buf.Bytes(), &doc); err != nil {
102 return nil, err
103 }
104
105
106 doc.Name = strings.TrimPrefix(doc.Name, "linkerd ")
107
108
109 if doc.Name != "linkerd" {
110 cmdList = append(cmdList, doc)
111 }
112
113 return cmdList, nil
114 }
115
116
117 func generateAnnotationsDocs() []annotationDoc {
118 return []annotationDoc{
119 {
120 Name: k8s.ProxyInjectAnnotation,
121 Description: "Controls whether or not a pod should be injected; accepted values are `enabled`, `disabled` and `ingress`",
122 },
123 {
124 Name: k8s.ProxyImageAnnotation,
125 Description: "Linkerd proxy container image name",
126 },
127 {
128 Name: k8s.ProxyImagePullPolicyAnnotation,
129 Description: "Docker image pull policy",
130 },
131 {
132 Name: k8s.ProxyInitImageAnnotation,
133 Description: "Linkerd init container image name",
134 },
135 {
136 Name: k8s.ProxyInitImageVersionAnnotation,
137 Description: "Linkerd init container image version",
138 },
139 {
140 Name: k8s.DebugImageAnnotation,
141 Description: "Linkerd debug container image name",
142 },
143 {
144 Name: k8s.DebugImageVersionAnnotation,
145 Description: "Linkerd debug container image version",
146 },
147 {
148 Name: k8s.DebugImagePullPolicyAnnotation,
149 Description: "Docker image pull policy for debug image",
150 },
151 {
152 Name: k8s.ProxyControlPortAnnotation,
153 Description: "Proxy port to use for control",
154 },
155 {
156 Name: k8s.ProxyIgnoreInboundPortsAnnotation,
157 Description: "Ports that should skip the proxy and send directly to the application. Comma-separated list of values, where each value can be a port number or a range `a-b`.",
158 },
159 {
160 Name: k8s.ProxyOpaquePortsAnnotation,
161 Description: "Ports that skip the proxy's protocol detection mechanism and are proxied opaquely. Comma-separated list of values, where each value can be a port number or a range `a-b`.",
162 },
163 {
164 Name: k8s.ProxyIgnoreOutboundPortsAnnotation,
165 Description: "Outbound ports that should skip the proxy. Comma-separated list of values, where each value can be a port number or a range `a-b`.",
166 },
167 {
168 Name: k8s.ProxyInboundPortAnnotation,
169 Description: "Proxy port to use for inbound traffic",
170 },
171 {
172 Name: k8s.ProxyAdminPortAnnotation,
173 Description: "Proxy port to serve metrics on",
174 },
175 {
176 Name: k8s.ProxyOutboundPortAnnotation,
177 Description: "Proxy port to use for outbound traffic",
178 },
179 {
180 Name: k8s.ProxyPodInboundPortsAnnotation,
181 Description: "Comma-separated list of (non-proxy) container ports exposed by the pod spec. Useful when other mutating webhooks inject sidecar containers after the proxy injector has run",
182 },
183 {
184 Name: k8s.ProxyCPURequestAnnotation,
185 Description: "Amount of CPU units that the proxy sidecar requests",
186 },
187 {
188 Name: k8s.ProxyMemoryRequestAnnotation,
189 Description: "Amount of Memory that the proxy sidecar requests",
190 },
191 {
192 Name: k8s.ProxyEphemeralStorageRequestAnnotation,
193 Description: "Used to override the requestEphemeralStorage config",
194 },
195 {
196 Name: k8s.ProxyCPULimitAnnotation,
197 Description: "Maximum amount of CPU units that the proxy sidecar can use",
198 },
199 {
200 Name: k8s.ProxyMemoryLimitAnnotation,
201 Description: "Maximum amount of Memory that the proxy sidecar can use",
202 },
203 {
204 Name: k8s.ProxyEphemeralStorageLimitAnnotation,
205 Description: "Used to override the limitEphemeralStorage config",
206 },
207 {
208 Name: k8s.ProxyUIDAnnotation,
209 Description: "Run the proxy under this user ID",
210 },
211 {
212 Name: k8s.ProxyGIDAnnotation,
213 Description: "Run the proxy under this group ID",
214 },
215 {
216 Name: k8s.ProxyLogLevelAnnotation,
217 Description: "Log level for the proxy",
218 },
219 {
220 Name: k8s.ProxyLogFormatAnnotation,
221 Description: "Log format (plain or json) for the proxy",
222 },
223 {
224 Name: k8s.ProxyAccessLogAnnotation,
225 Description: "Enables HTTP access logging in the proxy. Accepted values are `apache`, to output the access log in the Appache Common Log Format, and `json`, to output the access log in JSON.",
226 },
227 {
228 Name: k8s.ProxyEnableExternalProfilesAnnotation,
229 Description: "Enable service profiles for non-Kubernetes services",
230 },
231 {
232 Name: k8s.ProxyVersionOverrideAnnotation,
233 Description: "Tag to be used for the Linkerd proxy images",
234 },
235 {
236 Name: k8s.ProxyDefaultInboundPolicyAnnotation,
237 Description: "Proxy's default inbound policy",
238 },
239 {
240 Name: k8s.ProxyEnableDebugAnnotation,
241 Description: "Inject a debug sidecar for data plane debugging",
242 },
243 {
244 Name: k8s.ProxyOutboundConnectTimeout,
245 Description: "Used to configure the outbound TCP connection timeout in the proxy. Defaults to `1000ms`",
246 },
247 {
248 Name: k8s.ProxyInboundConnectTimeout,
249 Description: "Inbound TCP connection timeout in the proxy. Defaults to `100ms`",
250 },
251 {
252 Name: k8s.ProxyOutboundDiscoveryCacheUnusedTimeout,
253 Description: "Maximum time allowed before an unused outbound discovery result is evicted from the cache. Defaults to `5s`",
254 },
255 {
256 Name: k8s.ProxyInboundDiscoveryCacheUnusedTimeout,
257 Description: "Maximum time allowed before an unused inbound discovery result is evicted from the cache. Defaults to `90s`",
258 },
259 {
260 Name: k8s.ProxyDisableOutboundProtocolDetectTimeout,
261 Description: "When set to true, disables the protocol detection timeout on the outbound side of the proxy by setting it to a very high value",
262 },
263 {
264 Name: k8s.ProxyDisableInboundProtocolDetectTimeout,
265 Description: "When set to true, disables the protocol detection timeout on the inbound side of the proxy by setting it to a very high value",
266 },
267 {
268 Name: k8s.ProxyWaitBeforeExitSecondsAnnotation,
269 Description: "The proxy sidecar will stay alive for at least the given period after receiving SIGTERM signal from Kubernetes but no longer than pod's `terminationGracePeriodSeconds`. Defaults to `0`",
270 },
271 {
272 Name: k8s.ProxyAwait,
273 Description: "The application container will not start until the proxy is ready; accepted values are `enabled` and `disabled`",
274 },
275 {
276 Name: k8s.CloseWaitTimeoutAnnotation,
277 Description: "Sets nf_conntrack_tcp_timeout_close_wait. Accepts a duration string, e.g. `1m` or `3600s`",
278 },
279 {
280 Name: k8s.ProxySkipSubnetsAnnotation,
281 Description: "Comma-separated list of subnets in valid CIDR format that should be skipped by the proxy",
282 },
283 {
284 Name: k8s.ProxyShutdownGracePeriodAnnotation,
285 Description: "Grace period for graceful proxy shutdowns. If this timeout elapses before all open connections have completed, the proxy will terminate forcefully, closing any remaining connections.",
286 },
287 {
288 Name: k8s.ProxyEnableNativeSidecarAnnotation,
289 Description: "Enable KEP-753 native sidecars. This is an experimental feature. It requires Kubernetes >= 1.29. If enabled, .proxy.waitBeforeExitSeconds should not be used.",
290 },
291 }
292 }
293
View as plain text