Repository: canonical/microk8s

Issue:
TypeError: sequence item 10: expected str instance, NoneType found (microk8s dashboard-proxy)
#### Summary

I installed MicroK8s on Windows 10 [Version 10.0.19043.2130]. I can run `microk8s dashboard-proxy` inside `microk8s-vm` VM, but I can't run `microk8s dashboard-proxy` on the Host.

#### What Should Happen Instead?

It should run without error on host.

#### Reproduction Steps

On Windows PowerShell

1. `multipass launch --name 'microk8s-vm' --bridged --disk 50G --cpus 2 --mem 4G`
2. `multipass shell microk8s-vm`

On `microk8s-vm`

1. `sudo snap install microk8s --classic --channel 1.25/stable`

    ```txt
    microk8s (1.25/stable) v1.25.2 from Canonical✓ installed
    ```

3. `sudo microk8s status --wait-ready`

    ```txt
    microk8s is running
    high-availability: no
      datastore master nodes: 127.0.0.1:19001
      datastore standby nodes: none
    addons:
      enabled:
        ha-cluster           # (core) Configure high availability on the current node
        helm                 # (core) Helm - the package manager for Kubernetes
        helm3                # (core) Helm 3 - the package manager for Kubernetes
      disabled:
        cert-manager         # (core) Cloud native certificate management
        community            # (core) The community addons repository
        dashboard            # (core) The Kubernetes dashboard
        dns                  # (core) CoreDNS
        gpu                  # (core) Automatic enablement of Nvidia CUDA
        host-access          # (core) Allow Pods connecting to Host services smoothly
        hostpath-storage     # (core) Storage class; allocates storage from host directory
        ingress              # (core) Ingress controller for external access
        kube-ovn             # (core) An advanced network fabric for Kubernetes
        mayastor             # (core) OpenEBS MayaStor
        metallb              # (core) Loadbalancer for your Kubernetes cluster
        metrics-server       # (core) K8s Metrics Server for API access to service metrics
        observability        # (core) A lightweight observability stack for logs, traces and metrics
        prometheus           # (core) Prometheus operator for monitoring and logging
        rbac                 # (core) Role-Based Access Control for authorisation
        registry             # (core) Private image registry exposed on localhost:32000
        storage              # (core) Alias to hostpath-storage add-on, deprecated
    ```

4. `sudo microk8s enable dashboard`

    ```txt
    Infer repository core for addon dashboard
    Enabling Kubernetes Dashboard
    Infer repository core for addon metrics-server
    Enabling Metrics-Server
    serviceaccount/metrics-server created
    clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
    clusterrole.rbac.authorization.k8s.io/system:metrics-server created
    rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
    clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
    clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
    service/metrics-server created
    deployment.apps/metrics-server created
    apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
    clusterrolebinding.rbac.authorization.k8s.io/microk8s-admin created
    Metrics-Server is enabled
    Applying manifest
    serviceaccount/kubernetes-dashboard created
    service/kubernetes-dashboard created
    secret/kubernetes-dashboard-certs created
    secret/kubernetes-dashboard-csrf created
    secret/kubernetes-dashboard-key-holder created
    configmap/kubernetes-dashboard-settings created
    role.rbac.authorization.k8s.io/kubernetes-dashboard created
    clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
    rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
    clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
    deployment.apps/kubernetes-dashboard created
    service/dashboard-metrics-scraper created
    deployment.apps/dashboard-metrics-scraper created
    secret/microk8s-dashboard-token created

    If RBAC is not enabled access the dashboard using the token retrieved with:

    microk8s kubectl describe secret -n kube-system microk8s-dashboard-token

    Use this token in the https login UI of the kubernetes-dashboard service.

    In an RBAC enabled setup (microk8s enable RBAC) you need to create a user with restricted
    permissions as shown in:
    https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md
    ```

5. `sudo microk8s dashboard-proxy`

    ```txt
    Checking if Dashboard is running.
    Infer repository core for addon dashboard
    Infer repository core for addon metrics-server
    Waiting for Dashboard to come up.
    Trying to get token from microk8s-dashboard-token
    Waiting for secret token (attempt 0)
    Dashboard will be available at https://127.0.0.1:10443
    Use the following token to login:
    eyJhbGciOiJSUzI1NiI...(redacted)
    ```

6. `exit`

    Exit to the Windows PowerShell
    
On Windows PowerShell

1. `microk8s config > $env:LOCALAPPDATA\MicroK8s\config`

2. `microk8s dashboard-proxy`

    ```txt
    Checking if Dashboard is running.
    Infer repository core for addon dashboard
    Waiting for Dashboard to come up.
    Cannot find the dashboard secret.
    An unexpected error occurred.
    sequence item 10: expected str instance, NoneType found
    Traceback (most recent call last):
    File "cli\microk8s.py", line 57, in cli
    File "cli\microk8s.py", line 253, in dashboard_proxy
    File "vm_providers\_multipass\_multipass.py", line 54, in run
    File "vm_providers\_multipass\_multipass_command.py", line 232, in execute
    File "vm_providers\_multipass\_multipass_command.py", line 38, in _run_output
    TypeError: sequence item 10: expected str instance, NoneType found
    None
    ```

Run under Host. It will produce error.

![image](https://user-images.githubusercontent.com/88981/196414835-487b6eed-148e-45b1-bb2e-9a3f1597c874.png)

Run under Ubuntu VM. It's OK.

![image](https://user-images.githubusercontent.com/88981/196415890-2f7d5165-b663-4395-a5f2-c72641271fdb.png)


#### Introspection Report

[inspection-report-20221019_111239.tar.gz](https://github.com/canonical/microk8s/files/9816525/inspection-report-20221019_111239.tar.gz)

#### Can you suggest a fix?

No.

#### Are you interested in contributing with a fix?

yes if I can.

### More details

I checked the source code here:
https://github.com/canonical/microk8s/blob/e1d115f46a38ada6a2c5b236c9e26687b3529c45/installer/cli/microk8s.py#L308-L314

Here is my output:

```txt
$ microk8s.kubectl -n kube-system get secret
NAME                              TYPE                                  DATA   AGE
kubernetes-dashboard-certs        Opaque                                0      159m
microk8s-dashboard-token          kubernetes.io/service-account-token   3      159m
kubernetes-dashboard-csrf         Opaque                                1      159m
kubernetes-dashboard-key-holder   Opaque                                2      159m
```

It seems I don't have a `default-token` in the output. I don't know why I still can run `microk8s dashboard-proxy` inside Ubuntu Linux?



Discussion:
Hi @doggy8088 

This has been a change since Kubernetes 1.24, where secrets are no longer created by default for serviceaccounts, so there is no longer a `default-token` secret.

One workaround is to create the secret manually, using something like this:

```
microk8s kubectl apply -f <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: microk8s-dashboard-token
  namespace: kube-system
  annotations:
    kubernetes.io/service-account.name: "default"
type: kubernetes.io/service-account-token
EOF
```

This will ensure that the default token is there and will fix the `microk8s dashboard-proxy` command.

Note that `microk8s dashboard-proxy` works inside the VM because it handles this case, see https://github.com/canonical/microk8s/pull/3139.

In general, the code you pointed to should check whether the secret exists and act accordingly, instead of failing with an exception like it currently does. Contributions are welcome!

Resolving patch:
diff --git a/installer/cli/microk8s.py b/installer/cli/microk8s.py
--- a/installer/cli/microk8s.py
+++ b/installer/cli/microk8s.py
@@ -309,7 +309,7 @@ def dashboard_proxy() -> None:
         output = instance.run(command, hide_output=True)
         secret_name = None
         for line in output.split(b"\n"):
-            if line.startswith(b"default-token"):
+            if line.startswith(b"microk8s-dashboard-token"):
                 secret_name = line.split()[0].decode()
                 break
 


Test patch: