From 9ff042274f6c5f5979db57cfc32cfc41285d73e0 Mon Sep 17 00:00:00 2001 From: Ashley Dumaine Date: Wed, 14 Feb 2024 12:14:12 -0500 Subject: [PATCH] add mdbook-admonish and more troubleshooting notes --- docs/book/book.toml | 7 + docs/book/mdbook-admonish.css | 348 ++++++++++++++++++++++++ docs/book/src/developers/development.md | 36 ++- docs/book/src/topics/addons.md | 39 ++- docs/book/src/topics/getting-started.md | 13 +- docs/book/src/topics/troubleshooting.md | 64 ++++- 6 files changed, 472 insertions(+), 35 deletions(-) create mode 100644 docs/book/mdbook-admonish.css diff --git a/docs/book/book.toml b/docs/book/book.toml index cbbac2c9b..0cc4f41c4 100644 --- a/docs/book/book.toml +++ b/docs/book/book.toml @@ -10,3 +10,10 @@ build-dir = "public" [output.html] git-repository-url = "https://github.com/linode/cluster-api-provider-linode" +additional-css = ["./mdbook-admonish.css"] + +[preprocessor] + +[preprocessor.admonish] +command = "mdbook-admonish" +assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install` diff --git a/docs/book/mdbook-admonish.css b/docs/book/mdbook-admonish.css new file mode 100644 index 000000000..45aeff051 --- /dev/null +++ b/docs/book/mdbook-admonish.css @@ -0,0 +1,348 @@ +@charset "UTF-8"; +:is(.admonition) { + display: flow-root; + margin: 1.5625em 0; + padding: 0 1.2rem; + color: var(--fg); + page-break-inside: avoid; + background-color: var(--bg); + border: 0 solid black; + border-inline-start-width: 0.4rem; + border-radius: 0.2rem; + box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); +} +@media print { + :is(.admonition) { + box-shadow: none; + } +} +:is(.admonition) > * { + box-sizing: border-box; +} +:is(.admonition) :is(.admonition) { + margin-top: 1em; + margin-bottom: 1em; +} +:is(.admonition) > .tabbed-set:only-child { + margin-top: 0; +} +html :is(.admonition) > :last-child { + margin-bottom: 1.2rem; +} + +a.admonition-anchor-link { + display: none; + position: absolute; + left: -1.2rem; + padding-right: 1rem; +} +a.admonition-anchor-link:link, a.admonition-anchor-link:visited { + color: var(--fg); +} +a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { + text-decoration: none; +} +a.admonition-anchor-link::before { + content: "§"; +} + +:is(.admonition-title, summary.admonition-title) { + position: relative; + min-height: 4rem; + margin-block: 0; + margin-inline: -1.6rem -1.2rem; + padding-block: 0.8rem; + padding-inline: 4.4rem 1.2rem; + font-weight: 700; + background-color: rgba(68, 138, 255, 0.1); + print-color-adjust: exact; + -webkit-print-color-adjust: exact; + display: flex; +} +:is(.admonition-title, summary.admonition-title) p { + margin: 0; +} +html :is(.admonition-title, summary.admonition-title):last-child { + margin-bottom: 0; +} +:is(.admonition-title, summary.admonition-title)::before { + position: absolute; + top: 0.625em; + inset-inline-start: 1.6rem; + width: 2rem; + height: 2rem; + background-color: #448aff; + print-color-adjust: exact; + -webkit-print-color-adjust: exact; + mask-image: url('data:image/svg+xml;charset=utf-8,'); + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; +} +:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { + display: initial; +} + +details.admonition > summary.admonition-title::after { + position: absolute; + top: 0.625em; + inset-inline-end: 1.6rem; + height: 2rem; + width: 2rem; + background-color: currentcolor; + mask-image: var(--md-details-icon); + -webkit-mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; + transform: rotate(0deg); + transition: transform 0.25s; +} +details[open].admonition > summary.admonition-title::after { + transform: rotate(90deg); +} + +:root { + --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); +} + +:root { + --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); +} + +:is(.admonition):is(.admonish-note) { + border-color: #448aff; +} + +:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(68, 138, 255, 0.1); +} +:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #448aff; + mask-image: var(--md-admonition-icon--admonish-note); + -webkit-mask-image: var(--md-admonition-icon--admonish-note); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { + border-color: #00b0ff; +} + +:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 176, 255, 0.1); +} +:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00b0ff; + mask-image: var(--md-admonition-icon--admonish-abstract); + -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-info, .admonish-todo) { + border-color: #00b8d4; +} + +:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 184, 212, 0.1); +} +:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00b8d4; + mask-image: var(--md-admonition-icon--admonish-info); + -webkit-mask-image: var(--md-admonition-icon--admonish-info); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { + border-color: #00bfa5; +} + +:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 191, 165, 0.1); +} +:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00bfa5; + mask-image: var(--md-admonition-icon--admonish-tip); + -webkit-mask-image: var(--md-admonition-icon--admonish-tip); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { + border-color: #00c853; +} + +:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(0, 200, 83, 0.1); +} +:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #00c853; + mask-image: var(--md-admonition-icon--admonish-success); + -webkit-mask-image: var(--md-admonition-icon--admonish-success); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { + border-color: #64dd17; +} + +:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(100, 221, 23, 0.1); +} +:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #64dd17; + mask-image: var(--md-admonition-icon--admonish-question); + -webkit-mask-image: var(--md-admonition-icon--admonish-question); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { + border-color: #ff9100; +} + +:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 145, 0, 0.1); +} +:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff9100; + mask-image: var(--md-admonition-icon--admonish-warning); + -webkit-mask-image: var(--md-admonition-icon--admonish-warning); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { + border-color: #ff5252; +} + +:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 82, 82, 0.1); +} +:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff5252; + mask-image: var(--md-admonition-icon--admonish-failure); + -webkit-mask-image: var(--md-admonition-icon--admonish-failure); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-danger, .admonish-error) { + border-color: #ff1744; +} + +:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(255, 23, 68, 0.1); +} +:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #ff1744; + mask-image: var(--md-admonition-icon--admonish-danger); + -webkit-mask-image: var(--md-admonition-icon--admonish-danger); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-bug) { + border-color: #f50057; +} + +:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(245, 0, 87, 0.1); +} +:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #f50057; + mask-image: var(--md-admonition-icon--admonish-bug); + -webkit-mask-image: var(--md-admonition-icon--admonish-bug); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-example) { + border-color: #7c4dff; +} + +:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(124, 77, 255, 0.1); +} +:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #7c4dff; + mask-image: var(--md-admonition-icon--admonish-example); + -webkit-mask-image: var(--md-admonition-icon--admonish-example); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.admonish-quote, .admonish-cite) { + border-color: #9e9e9e; +} + +:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { + background-color: rgba(158, 158, 158, 0.1); +} +:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { + background-color: #9e9e9e; + mask-image: var(--md-admonition-icon--admonish-quote); + -webkit-mask-image: var(--md-admonition-icon--admonish-quote); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +.navy :is(.admonition) { + background-color: var(--sidebar-bg); +} + +.ayu :is(.admonition), +.coal :is(.admonition) { + background-color: var(--theme-hover); +} + +.rust :is(.admonition) { + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { + color: var(--sidebar-fg); +} diff --git a/docs/book/src/developers/development.md b/docs/book/src/developers/development.md index d58b94eda..235ce34a7 100644 --- a/docs/book/src/developers/development.md +++ b/docs/book/src/developers/development.md @@ -72,8 +72,10 @@ SKIP_GIT_PUSH_HOOK=1 git push ### Setting up the environment -You must have your LINODE\_TOKEN set as outlined in the +```admonish warning +Ensure you have your `LINODE_TOKEN` set as outlined in the [getting started prerequisites](../topics/getting-started.md#Prerequisites) section. +``` All development dependencies should be taken care of via Devbox and/or make target dependencies. @@ -95,7 +97,7 @@ dependencies will install any missing dependencies if needed when running outside of a devbox shell. ### Using tilt -To build a kind cluster and start Tilt, just run: +To build a kind cluster and start Tilt, simply run: ```shell make tilt-cluster ``` @@ -141,7 +143,11 @@ ssh-keygen -t rsa -b 4096 -f "${SSH_KEY_FILE}" -N '' 1>/dev/null export LINODE_SSH_KEY="$(cat "${SSH_KEY_FILE}.pub)" ``` -⚠️ Please note the templates require the use of `clusterctl generate` to substitute the environment variables properly. +```admonish warning +Please note the templates require the use of `clusterctl generate` to substitute the environment variables properly. + +Ensure each of the above required environment variables are set before running `clusterctl generate` +``` #### Creating the workload cluster @@ -155,14 +161,12 @@ clusterctl generate cluster $CLUSTER_NAME \ | kubectl apply -f - ``` -This will provision the cluster with the CNI defaulted to cilium. +This will provision the cluster with the CNI defaulted to [cilium](../topics/addons.md#cilium) +and the [linode-ccm](../topics/addons.md#ccm) installed. -Once the cluster control-plane is reachable, you'll need to install -the linode-ccm in order for the Node `InternalIP` and `ExternalIP` to be set correctly. -Please refer to the [CCM](../topics/addons.md#ccm) section. This is a temporary manual -step until the linode-ccm can be installed via CAAPH (see [this GitHub issue](https://github.com/linode/cluster-api-provider-linode/issues/101)). - -> For any issues, please refer to the [troubleshooting guide](../topics/troubleshooting.md). +```admonish question title="" +For any issues, please refer to the [troubleshooting guide](../topics/troubleshooting.md). +``` #### Cleaning up the workload cluster @@ -172,17 +176,21 @@ To delete the cluster, simply run: kubectl delete cluster $CLUSTER_NAME ``` -> For any issues, please refer to the [troubleshooting guide](../topics/troubleshooting.md). +```admonish question title="" +For any issues, please refer to the [troubleshooting guide](../topics/troubleshooting.md). +``` ### Automated Testing #### E2E Testing -To run E2E locally set `LINODE_TOKEN and run: +To run E2E locally run: ```bash make e2etest ``` -This command creates a Kind cluster, and executes all the defined tests. +This command creates a KIND cluster, and executes all the defined tests. -⚠️ Please ensure you have [increased maximum open files on your host](https://kind.sigs.k8s.io/docs/user/known-issues/#pod-errors-due-to-too-many-open-files) +```admonish warning +Please ensure you have [increased maximum open files on your host](https://kind.sigs.k8s.io/docs/user/known-issues/#pod-errors-due-to-too-many-open-files) +``` \ No newline at end of file diff --git a/docs/book/src/topics/addons.md b/docs/book/src/topics/addons.md index e608d0c9f..dfd8cd504 100644 --- a/docs/book/src/topics/addons.md +++ b/docs/book/src/topics/addons.md @@ -2,23 +2,34 @@ This section provides examples for addons for self-managed clusters. +```admonish note +Currently, all addons are installed via +[Cluster API Addon Provider Helm (CAAPH)](https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm). + +CAAPH is installed by default in the KIND cluster created by `make tilt-cluster`. + +For more information, please refer to the +[CAAPH Quick Start](https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm/blob/main/docs/quick-start.md). +``` + # CNI +```admonish warning By default, the CNI plugin is not installed for self-managed clusters. -[Cluster API Addon Provider Helm (CAAPH)](https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm) -can be used to install a CNI via a Helm Chart, which is installed by default in -the KIND cluster created by `make tilt-cluster` +To install a CNI, ensure that your `Cluster` is labeled with one of the below CNI options. +``` ## Cilium -To install [Cilium](https://cilium.io/) on a self-managed cluster, -simply apply the `cni: cilium` label on the `Cluster` resource. -``` -kubectl label cluster $CLUSTER_NAME cni=cilium` +To install [Cilium](https://cilium.io/) on a self-managed cluster, simply apply the `cni: cilium` +label on the `Cluster` resource if not already present. + +```bash +kubectl label cluster $CLUSTER_NAME cni=cilium ``` -Cilium will be automatically installed via CAAPH into the labeled self-managed cluster. +Cilium will then be automatically installed via CAAPH into the labeled self-managed cluster. # CCM @@ -26,14 +37,12 @@ In order for the `InternalIP` and `ExternalIP` of the provisioned Nodes to be se the [linode-cloud-controller-manager (linode-ccm)](https://github.com/linode/linode-cloud-controller-manager) must be installed into provisioned clusters. -At this time, CAAPH cannot install the linode-ccm so it must be manually generated and installed into -a self-managed cluster. -Please refer to the section on [generating a manifest for deployment](https://github.com/linode/linode-cloud-controller-manager?tab=readme-ov-file#generating-a-manifest-for-deployment). -Once you have generated the `ccm-linode.yaml`, get the kubeconfig for the self-managed cluster -via `clusterctl` and apply it: +To install the linode-ccm on a self-managed cluster, simply apply the `ccm: linode` +label on the `Cluster` resource if not already present. ```bash -clusterctl get kubeconfig $CLUSTER_NAME > $CLUSTER_NAME-kubeconfig.yaml -kubectl apply -f ccm-linode.yaml --kubeconfig $CLUSTER_NAME-kubeconfig.yaml +kubectl label cluster $CLUSTER_NAME ccm=linode ``` + +The linode-ccm will then be automatically installed via CAAPH into the labeled self-managed cluster. \ No newline at end of file diff --git a/docs/book/src/topics/getting-started.md b/docs/book/src/topics/getting-started.md index b2047dada..f159d76c0 100644 --- a/docs/book/src/topics/getting-started.md +++ b/docs/book/src/topics/getting-started.md @@ -1,9 +1,7 @@ -# Getting started with cluster-api-provider-linode +# Getting started with CAPL ## Prerequisites -### Requirements - - A [Linode account](https://linode.com/) - A Personal Access Token (PAT) created via [the Linode Cloud Manager](https://cloud.linode.com/profile/tokens). Make sure to create the token with at least the following read/write permissions (or "all"): @@ -14,14 +12,19 @@ Make sure to create the token with at least the following read/write permissions - VPCs - IPs +```admonish question +For more information please see the +[Linode Guide](https://www.linode.com/docs/products/tools/api/guides/manage-api-tokens/#create-an-api-token). +``` + ## Setting up your Linode environment Once you have provisioned your PAT, save it in an environment variable: ```bash -export LINODE_TOKEN="LinodePAT" +export LINODE_TOKEN="" ``` ## Building your first cluster -Please contine from the [setting up the environment](../developers/development.md#setting-up-the-environment) +Please continue from the [setting up the environment](../developers/development.md#setting-up-the-environment) section for creating your first Kubernetes cluster on Linode using Cluster API. diff --git a/docs/book/src/topics/troubleshooting.md b/docs/book/src/topics/troubleshooting.md index 6d8559af7..afd95a905 100644 --- a/docs/book/src/topics/troubleshooting.md +++ b/docs/book/src/topics/troubleshooting.md @@ -1,7 +1,7 @@ # Troubleshooting Guide This guide covers common issues users might run into when using Cluster API Provider Linode. -This list is work-in-progress, please feel free to open a PR to add this guideif you find +This list is work-in-progress, please feel free to open a PR to add this guide if you find that useful information is missing. ## Examples of common issues @@ -9,5 +9,67 @@ that useful information is missing. ### No Linode resources are getting created This could be due to the `LINODE_TOKEN` either not being set in your environment or expired. +If expired, [provision a new token](../topics/getting-started.md#prerequisites) and optionally +set the "Expiry" to "Never" (default expiry is 6 months). +### One or more control plane replicas are missing + +Take a look at the `KubeadmControlPlane` controller logs and look for any potential errors: + +```bash +kubectl logs deploy/capi-kubeadm-control-plane-controller-manager -n capi-kubeadm-control-plane-system manager +``` + +In addition, make sure all pods on the workload cluster are healthy, including pods in the `kube-system` namespace. + +Otherwise, [ensure that the linode-ccm is installed on your workload cluster via CAAPH](../topics/addons.md#ccm). + +### Nodes are in NotReady state + +Make sure [a CNI is installed on the workload cluster](../topics/addons.md#cni) +and that all the pods on the workload cluster are in running state. + +If the Cluster is labeled with `cni: cilium`, check that the cilium `HelmChartProxy` is installed in +the management cluster and that the `HelmChartProxy` is in a `Ready` state: + +```bash +kubectl get cluster $CLUSTER_NAME --show-labels +``` + +```bash +kubectl get helmchartproxies +``` + +## Checking CAPI and CAPL resources + +To check the progression of all CAPI and CAPL resources on the management cluster you can run: + +```bash +kubectl get cluster-api +``` + +## Looking at the CAPL controller logs + +To check the CAPL controller logs on the management cluster, run: + +```bash +kubectl logs deploy/cluster-api-provider-linode-controller-manager -n cluster-api-provider-linode-system manager +``` + +### Checking cloud-init logs (Debian / Ubuntu) + +[Cloud-init](https://www.linode.com/docs/guides/applications/configuration-management/cloud-init/) +logs can provide more information on any issues that happened when running the bootstrap script. + +```admonish warning +Not all Debian and Ubuntu images available from Linode support cloud-init! Please see the +[Availability section of the Linode Metadata Service Guide](https://www.linode.com/docs/products/compute/compute-instances/guides/metadata/#availability). + +You can also see which images have cloud-init support via the [linode-cli](https://www.linode.com/docs/products/tools/cli/get-started/): + +`linode-cli images list | grep cloud-init` + +``` + +Please refer to the [Troubleshoot Metadata and Cloud-Init section of the Linode Metadata Service Guide](https://www.linode.com/docs/products/compute/compute-instances/guides/metadata/?tabs=linode-api%2Cmacos#troubleshoot-metadata-and-cloud-init).