Closed Nalum closed 8 months ago
I've tried to render the markdown from your example and looks like the multi-line values break into rows. Maybe we need to wrap the multi-line into code block "````"?
Yeah, I'll try fix that shortly. I was in the process of getting it into a single line, will try the code block syntax.
Using a code block didn't work, still split across multiple lines. But marshaling to a single line of JSON works, not very readable though...
| FIELD | TYPE | DEFAULT | DESCRIPTION |
|--------------------------------------------------------------------------|----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
| `logLevel` | `int` | `2` | |
| `rbac.enabled` | `bool` | `true` | |
| `controller.monitoring.serviceMonitor.targetPort` | `(int|string)` | `http-metrics` | |
| `controller.volumeMounts` | `list` | `[{"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount","name":"serviceaccount-token","readOnly":true}]` | |
| `controller.volumes` | `list` | `[{"name":"serviceaccount-token","projected":{"defaultMode":444,"sources":[{"serviceAccountToken":{"expirationSeconds":3607,"path":"token"}},{"configMap":{"name":"kube-root-ca.crt","items":[{"key":"ca.crt","path":"ca.crt"}]}},{"downwardAPI":{"items":[{"path":"namespace","fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}]}}]}}]` | |
| `webhook.hostNetwork` | `bool` | `false` | |
| `webhook.securePort` | `int` | `10250` | |
| `webhook.timeoutSeconds` | `int` | `10` | |
| `webhook.image.repository` | `string` | `quay.io/jetstack/cert-manager-webhook` | |
| `webhook.image.tag` | `string` | `v1.13.2` | |
| `webhook.image.digest` | `string` | `sha256:0a9470447ebf1d3ff1c172e19268be12dc26125ff83320d456f6826c677c0ed2` | |
| `webhook.image.pullPolicy` | `string` | `IfNotPresent` | |
| `webhook.networkPolicy` | `struct` | `{"ingress":[{"from":[{"ipBlock":{"cidr":"0.0.0.0/0"}}]}],"egress":[{"ports":[{"port":80,"protocol":"TCP"},{"port":443,"protocol":"TCP"},{"port":53,"protocol":"TCP"},{"port":53,"protocol":"UDP"},{"port":6443,"protocol":"TCP"}],"to":[{"ipBlock":{"cidr":"0.0.0.0/0"}}]}]}` | |
| `webhook.volumeMounts` | `list` | `[{"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount","name":"serviceaccount-token","readOnly":true}]` | |
| `webhook.volumes` | `list` | `[{"name":"serviceaccount-token","projected":{"defaultMode":444,"sources":[{"serviceAccountToken":{"expirationSeconds":3607,"path":"token"}},{"configMap":{"name":"kube-root-ca.crt","items":[{"key":"ca.crt","path":"ca.crt"}]}},{"downwardAPI":{"items":[{"path":"namespace","fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}]}}]}}]` | |
| `caInjector.automountServiceAccountToken` | `bool` | `false` | |
| `test.startupAPICheck.replicas` | `int` | `1` | |
| `test.startupAPICheck.securityContext.runAsNonRoot` | `bool` | `true` | |
| `test.startupAPICheck.securityContext.seccompProfile.type` | `string` | `RuntimeDefault` | |
| `test.startupAPICheck.serviceAccount.automountServiceAccountToken` | `bool` | `false` | |
| `test.startupAPICheck.service.type` | `string` | `ClusterIP` | |
| `test.startupAPICheck.volumeMounts` | `list` | `[{"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount","name":"serviceaccount-token","readOnly":true}]` | |
| `test.startupAPICheck.volumes` | `list` | `[{"name":"serviceaccount-token","projected":{"defaultMode":444,"sources":[{"serviceAccountToken":{"expirationSeconds":3607,"path":"token"}},{"configMap":{"name":"kube-root-ca.crt","items":[{"key":"ca.crt","path":"ca.crt"}]}},{"downwardAPI":{"items":[{"path":"namespace","fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}]}}]}}]` | |
In the field names do we want to have them separated by :
as they would be in cue? e.g. test: startupAPICheck: service: type:
Figured out how to pull the comment associated with a config field:
FIELD | TYPE | DEFAULT | DESCRIPTION |
---|---|---|---|
test.enabled |
bool |
true |
|
test.startupAPICheck.backoffLimit |
int |
4 |
|
test.startupAPICheck.automountServiceAccountToken |
bool |
false |
automountServiceAccountToken indicates whether a service account token should be automatically mounted. |
test.startupAPICheck.containerSecurityContext.capabilities.drop |
list |
["ALL"] |
Removed capabilities +optional |
test.startupAPICheck.containerSecurityContext.runAsNonRoot |
bool |
true |
Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. +optional |
test.startupAPICheck.containerSecurityContext.readOnlyRootFilesystem |
bool |
true |
Whether this container has a read-only root filesystem. Default is false. Note that this field cannot be set when spec.os.name is windows. +optional |
test.startupAPICheck.containerSecurityContext.allowPrivilegeEscalation |
bool |
false |
AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows. +optional |
test.startupAPICheck.enableServiceLinks |
bool |
false |
enableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links. |
test.startupAPICheck.image.repository |
string |
"quay.io/jetstack/cert-manager-ctl" |
Repository is the address of a container registry repository. An image repository is made up of slash-separated name components, optionally prefixed by a registry hostname and port in the format [HOST[:PORT_NUMBER]/]PATH. |
test.startupAPICheck.image.tag |
string |
"v1.13.2" |
Tag identifies an image in the repository. A tag name may contain lowercase and uppercase characters, digits, underscores, periods and dashes. A tag name may not start with a period or a dash and may contain a maximum of 128 characters. |
test.startupAPICheck.image.digest |
string |
"sha256:4d9fce2c050eaadabedac997d9bd4a003341e9172c3f48fae299d94fa5f03435" |
Digest uniquely and immutably identifies an image in the repository. Spec: https://github.com/opencontainers/image-spec/blob/main/descriptor.md#digests. |
test.startupAPICheck.image.pullPolicy |
string |
"IfNotPresent" |
PullPolicy defines the pull policy for the image. By default, it is set to IfNotPresent. |
test.startupAPICheck.timeout |
string |
"1m" |
Timeout for 'kubectl check api' command |
Should I put Description
before Default
?
I think we should be using :
as separat for fields so it's valid CUE. Also let's remove +optional
and +required
if these are in a dedicated line comment.
Should this also be updated to have -o (markdown|yaml|json)
?
I would go for --output README.md
and when a .md
file is specified, I would replace the existing table if it exists at the end of the doc, if not, I would append it.
@Nalum can you please update the PR description and put there not in code blocks, but as markdown the cert-manager table in its latest form.
@stefanprodan will do, just going to update the logic a bit more.
@stefanprodan are you happy with the command structure, timoni mod config
, or do you have something else you'd prefer?
I would go with timoni mod show config
@stefanprodan I have updated this so now you can set +nodoc
and +required
, ~however I cannot identify these as a separate dedicated line so have used strings.HasSuffix
:~ ~Actually I could look for \n+nodoc\n$
or \n+required\n$
...~ scratch that, I've found another way.
I've also had to update the timoni core api files and the timoni.cue
file with +nodoc
comments to hide certain fields as they were not being hidden by adding it to the #Config
in templates
. I'm happy to apply this to where needed in this PR or another if you're happy with this.
This adds support for creating a markdown table generated from the configuration cue structure in a module with
timoni mod show config
.Fix: https://github.com/stefanprodan/timoni/issues/168
The command will output the table to
os.Stdout
by default, however you can provide a file name to the flag-o
or--output
where the table will be written to. If the file is markdown (i.e. has the file extention.md
or.markdown
) we look for the heading## Configuration
and then a table within this heading which will be replaced. If the file is not markdown the table will be appended to the file.The below is an example of output generated from the blueprint module and you can look at the cert-manager-module README for an example of something with more complexity.
timoni: instance: config:
struct
{"kubeVersion": "1.27.5","clusterVersion": {"major": 1,"minor": 27}, "moduleVersion": "0.0.0-devel","metadata": {"name": "module-name","namespace": "default","labels": {"app.kubernetes.io/name": "module-name","app.kubernetes.io/version": "0.0.0-devel","app.kubernetes.io/managed-by": "timoni"}}, "selector": {"labels": {"app.kubernetes.io/name": "module-name"}}, "image": {"repository": "docker.io/nginx","tag": "1-alpine","digest": "","pullPolicy": "IfNotPresent","reference": "docker.io/nginx:1-alpine"}, "pod": {"affinity": {"nodeAffinity": {"requiredDuringSchedulingIgnoredDuringExecution": {"nodeSelectorTerms": [{"matchExpressions": [{"key": "kubernetes.io/os","operator": "In","values": ["linux"]}]}]}}}}, "resources": {"requests": {"cpu": "10m","memory": "32Mi"}}, "replicas": 1,"securityContext": {"capabilities": {"drop": ["ALL"],"add": ["CHOWN","NET_BIND_SERVICE","SETGID","SETUID"]}, "privileged": false,"allowPrivilegeEscalation": false}, "service": {"port": 80}}
kubeVersion:
string
"1.27.5"
clusterVersion:
struct
{"major": 1,"minor": 27}
clusterVersion: major:
int
1
clusterVersion: minor:
int
27
moduleVersion:
string
"0.0.0-devel"
app.kubernetes.io/version
label.metadata:
struct
{"name": "module-name","namespace": "default","labels": {"app.kubernetes.io/name": "module-name","app.kubernetes.io/version": "0.0.0-devel","app.kubernetes.io/managed-by": "timoni"}}
metadata.name
andmetadata.namespace
fields are set from the user-supplied instance name and namespace.metadata: name:
string
"module-name"
metadata: namespace:
string
"default"
metadata: labels:
struct
{"app.kubernetes.io/name": "module-name","app.kubernetes.io/version": "0.0.0-devel","app.kubernetes.io/managed-by": "timoni"}
metadata.labels
to all resources. Theapp.kubernetes.io/name
andapp.kubernetes.io/version
labels are automatically generated and can't be overwritten.metadata: labels: "app.kubernetes.io/name":
string
"module-name"
metadata: labels: "app.kubernetes.io/version":
string
"0.0.0-devel"
metadata: labels: "app.kubernetes.io/managed-by":
string
"timoni"
selector:
struct
{"labels": {"app.kubernetes.io/name": "module-name"}}
app.kubernetes.io/name
label selector is automatically generated from the instance name and can't be overwritten.selector: labels:
struct
{"app.kubernetes.io/name": "module-name"}
selector: labels: "app.kubernetes.io/name":
string
"module-name"
image:
struct
{"repository": "docker.io/nginx","tag": "1-alpine","digest": "","pullPolicy": "IfNotPresent","reference": "docker.io/nginx:1-alpine"}
image: repository:
string
"docker.io/nginx"
image: tag:
string
"1-alpine"
image: digest:
string
""
image: pullPolicy:
string
"IfNotPresent"
image: reference:
string
"docker.io/nginx:1-alpine"
pod:
struct
{"affinity": {"nodeAffinity": {"requiredDuringSchedulingIgnoredDuringExecution": {"nodeSelectorTerms": [{"matchExpressions": [{"key": "kubernetes.io/os","operator": "In","values": ["linux"]}]}]}}}}
pod: affinity:
struct
{"nodeAffinity": {"requiredDuringSchedulingIgnoredDuringExecution": {"nodeSelectorTerms": [{"matchExpressions": [{"key": "kubernetes.io/os","operator": "In","values": ["linux"]}]}]}}}
resources:
struct
{"requests": {"cpu": "10m","memory": "32Mi"}}
resources: requests:
struct
{"cpu": "10m","memory": "32Mi"}
resources: requests: cpu:
string
"10m"
resources: requests: memory:
string
"32Mi"
replicas:
int
1
securityContext:
struct
{"capabilities": {"drop": ["ALL"],"add": ["CHOWN","NET_BIND_SERVICE","SETGID","SETUID"]}, "privileged": false,"allowPrivilegeEscalation": false}
securityContext: capabilities:
struct
{"drop": ["ALL"],"add": ["CHOWN","NET_BIND_SERVICE","SETGID","SETUID"]}
securityContext: capabilities: drop:
list
["ALL"]
securityContext: capabilities: add:
list
["CHOWN","NET_BIND_SERVICE","SETGID","SETUID"]
securityContext: privileged:
bool
false
securityContext: allowPrivilegeEscalation:
bool
false
service:
struct
{"port": 80}
service: port:
int
80