Repository: kubernetes/minikube
Pull request #14315 (2022-06-10 11:58:44)

Addon: add headlamp
[Headlamp](https://github.com/kinvolk/headlamp) is an opensource easy-to-use and extensible Kubernetes web UI. 
Headlamp supports the following features. 

- Vendor independent / generic Kubernetes UI
- Works in-cluster, or locally as a desktop app
- Multi-cluster
- Extensible through plugins
- UI controls reflecting user roles (no deletion/update if not allowed)
- Clean & modern UI
- Cancellable creation/update/deletion operations
- Logs, exec, and resource editor with documentation
- Read-write / interactive (actions based on permissions)


linux-foundation-easycla[bot]:  <a href="https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/18706487/56353740/14315/#/?version=2"><img src="https://s3.amazonaws.com/cla-project-logo-prod/cla-not-signed.svg" alt="CLA Not Signed" align="left" height="28" width="328"></a><br/><br /><ul><li><a href='https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/18706487/56353740/14315/#/?version=2' target='_blank'>:x:</a> - login: @yolossn / name: S Santhosh Nagaraj . The commit (1fdd8db55e886e3f8f49322028f30037a1e809c1) is not authorized under a signed CLA. <a href='https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/18706487/56353740/14315/#/?version=2' target='_blank'>Please click here to be authorized</a>. For further assistance with EasyCLA, <a href='https://jira.linuxfoundation.org/servicedesk/customer/portal/4' target='_blank'>please submit a support request ticket</a>.</li></ul>
k8s-ci-robot: Welcome @yolossn! <br><br>It looks like this is your first PR to <a href='https://github.com/kubernetes/minikube'>kubernetes/minikube</a> 🎉. Please refer to our [pull request process documentation](https://git.k8s.io/community/contributors/guide/pull-requests.md) to help your PR have a smooth ride to approval. <br><br>You will be prompted by a bot to use commands during the review process. Do not be afraid to follow the prompts! It is okay to experiment. [Here is the bot commands documentation](https://go.k8s.io/bot-commands). <br><br>You can also check if kubernetes/minikube has [its own contribution guidelines](https://github.com/kubernetes/minikube/tree/master/CONTRIBUTING.md). <br><br>You may want to refer to our [testing guide](https://git.k8s.io/community/contributors/devel/sig-testing/testing.md) if you run into trouble with your tests not passing. <br><br>If you are having difficulty getting your pull request seen, please follow the [recommended escalation practices](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#why-is-my-pull-request-not-getting-reviewed). Also, for tips and tricks in the contribution process you may want to read the [Kubernetes contributor cheat sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet/README.md). We want to make sure your contribution gets all the attention it needs! <br><br>Thank you, and welcome to Kubernetes. :smiley:
k8s-ci-robot: Hi @yolossn. Thanks for your PR.

I'm waiting for a [kubernetes](https://github.com/orgs/kubernetes/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fminikube).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/minikube/pull/14315#" title="Author self-approved">yolossn</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **afbjorklund** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @afbjorklund` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fminikube).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes/minikube/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["afbjorklund"]} -->
minikube-bot: Can one of the admins verify this patch?
k8s-ci-robot: @yolossn: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
minikube-pr-bot: **kvm2 driver with docker runtime**
```
+----------------+----------+---------------------+
|    COMMAND     | MINIKUBE | MINIKUBE (PR 14315) |
+----------------+----------+---------------------+
| minikube start | 50.9s    | 50.1s               |
| enable ingress | 27.7s    | 28.1s               |
+----------------+----------+---------------------+
```

<details>

Times for minikube (PR 14315) start: 50.5s 50.5s 50.9s 49.8s 48.6s 
Times for minikube start: 51.6s 50.0s 51.2s 50.4s 51.3s 

Times for minikube ingress: 29.6s 25.2s 25.6s 29.1s 29.1s 
Times for minikube (PR 14315) ingress: 28.6s 28.1s 28.6s 28.6s 26.6s 

</details>

**docker driver with docker runtime**
```
+----------------+----------+---------------------+
|    COMMAND     | MINIKUBE | MINIKUBE (PR 14315) |
+----------------+----------+---------------------+
| minikube start | 28.8s    | 24.9s               |
| enable ingress | 22.1s    | 21.5s               |
+----------------+----------+---------------------+
```

<details>

Times for minikube start: 46.3s 24.3s 23.9s 24.6s 24.8s 
Times for minikube (PR 14315) start: 25.3s 24.6s 24.9s 25.2s 24.5s 

Times for minikube (PR 14315) ingress: 21.4s 21.4s 21.4s 21.9s 21.4s 
Times for minikube ingress: 22.4s 21.9s 21.9s 22.4s 21.9s 

</details>

**docker driver with containerd runtime**
```
+----------------+----------+---------------------+
|    COMMAND     | MINIKUBE | MINIKUBE (PR 14315) |
+----------------+----------+---------------------+
| minikube start | 32.7s    | 30.6s               |
| enable ingress | 19.2s    | 22.4s               |
+----------------+----------+---------------------+
```

<details>

Times for minikube (PR 14315) start: 29.3s 32.6s 28.4s 28.9s 33.7s 
Times for minikube start: 30.1s 33.7s 32.9s 34.7s 32.1s 

Times for minikube (PR 14315) ingress: 30.9s 17.9s 22.4s 21.9s 18.9s 
Times for minikube ingress: 22.4s 18.0s 18.9s 17.9s 18.9s 

</details>
yolossn: Hey @spowelljr I looked into why some of the checks are failing and it doesn't seem to be related to the changes, Do you think a  rerun will help in this case? Or is there something that I am missing?
spowelljr: Hi @yolossn, we have several flakey tests so we expect many to fail. We're having an issue with our Docker Linux CI right now, so once we get that fixed I'll rerun the tests.
spowelljr: Hi @yolossn, could you pull the latest `master` of minikube and then rebase your PR, that will pull in the CI fix and will rerun your tests, thanks

Patch:
diff --git a/cmd/minikube/cmd/config/enable.go b/cmd/minikube/cmd/config/enable.go
index 28da1eb43..36c38c1ed 100644
--- a/cmd/minikube/cmd/config/enable.go
+++ b/cmd/minikube/cmd/config/enable.go
@@ -67,6 +67,29 @@ var addonsEnableCmd = &cobra.Command{
 
 	minikube{{.profileArg}} addons enable metrics-server	
 
+`, out.V{"profileArg": tipProfileArg})
+
+		}
+		if addon == "headlamp" {
+			out.Styled(style.Tip, `To access Headlamp, use the following command:
+minikube service headlamp -n headlamp
+
+`)
+			out.Styled(style.Tip, `To authenticate in Headlamp, fetch the Authentication Token using the following command:
+
+export SECRET=$(kubectl get secrets --namespace headlamp -o custom-columns=":metadata.name" | grep "headlamp-token")
+kubectl get secret $SECRET --namespace headlamp --template=\{\{.data.token\}\} | base64 --decode
+			
+`)
+
+			tipProfileArg := ""
+			if ClusterFlagValue() != constants.DefaultClusterName {
+				tipProfileArg = fmt.Sprintf(" -p %s", ClusterFlagValue())
+			}
+			out.Styled(style.Tip, `Headlamp can display more detailed information when metrics-server is installed. To install it, run:
+
+minikube{{.profileArg}} addons enable metrics-server	
+
 `, out.V{"profileArg": tipProfileArg})
 
 		}
diff --git a/deploy/addons/assets.go b/deploy/addons/assets.go
index 84b6b644d..209f0560d 100644
--- a/deploy/addons/assets.go
+++ b/deploy/addons/assets.go
@@ -147,4 +147,8 @@ var (
 	// InAccelAssets assets for inaccel addon
 	//go:embed inaccel/fpga-operator.yaml.tmpl
 	InAccelAssets embed.FS
+
+	// HeadlampAssets assets for headlamp addon
+	//go:embed headlamp/*.yaml headlamp/*.tmpl
+	HeadlampAssets embed.FS
 )
diff --git a/deploy/addons/headlamp/headlamp-clusterrolebinding.yaml b/deploy/addons/headlamp/headlamp-clusterrolebinding.yaml
new file mode 100644
index 000000000..1f516989e
--- /dev/null
+++ b/deploy/addons/headlamp/headlamp-clusterrolebinding.yaml
@@ -0,0 +1,18 @@
+---
+# ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: headlamp-admin
+  namespace: headlamp
+  labels:
+    app.kubernetes.io/name: headlamp
+    app.kubernetes.io/instance: headlamp
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: headlamp
+  namespace: headlamp
diff --git a/deploy/addons/headlamp/headlamp-deployment.yaml.tmpl b/deploy/addons/headlamp/headlamp-deployment.yaml.tmpl
new file mode 100644
index 000000000..63da3b343
--- /dev/null
+++ b/deploy/addons/headlamp/headlamp-deployment.yaml.tmpl
@@ -0,0 +1,42 @@
+---
+# Deployment
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: headlamp
+  namespace: headlamp
+  labels:
+    app.kubernetes.io/name: headlamp
+    app.kubernetes.io/instance: headlamp
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: headlamp
+      app.kubernetes.io/instance: headlamp
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/name: headlamp
+        app.kubernetes.io/instance: headlamp
+    spec:
+      serviceAccountName: headlamp
+      containers:
+        - name: headlamp
+          image: {{.CustomRegistries.Headlamp  | default .ImageRepository | default .Registries.Headlamp }}{{.Images.Headlamp}}
+          imagePullPolicy: IfNotPresent
+          args:
+            - "-in-cluster"
+            - "-plugins-dir=/headlamp/plugins"
+          ports:
+            - name: http
+              containerPort: 4466
+              protocol: TCP
+          livenessProbe:
+            httpGet:
+              path: /
+              port: http
+          readinessProbe:
+            httpGet:
+              path: /
+              port: http
diff --git a/deploy/addons/headlamp/headlamp-namespace.yaml b/deploy/addons/headlamp/headlamp-namespace.yaml
new file mode 100644
index 000000000..85d4ae0a2
--- /dev/null
+++ b/deploy/addons/headlamp/headlamp-namespace.yaml
@@ -0,0 +1,6 @@
+---
+# Namespace
+apiVersion: v1 
+kind: Namespace 
+metadata:
+  name: headlamp
diff --git a/deploy/addons/headlamp/headlamp-service.yaml b/deploy/addons/headlamp/headlamp-service.yaml
new file mode 100644
index 000000000..1eca749b8
--- /dev/null
+++ b/deploy/addons/headlamp/headlamp-service.yaml
@@ -0,0 +1,21 @@
+--- 
+# Service 
+apiVersion: v1
+kind: Service
+metadata:
+  name: headlamp
+  namespace: headlamp
+  labels:
+    app.kubernetes.io/name: headlamp
+    app.kubernetes.io/instance: headlamp
+    kubernetes.io/minikube-addons-endpoint: headlamp
+spec:
+  type: NodePort
+  ports:
+    - port: 80
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    app.kubernetes.io/name: headlamp
+    app.kubernetes.io/instance: headlamp
diff --git a/deploy/addons/headlamp/headlamp-serviceaccount.yaml b/deploy/addons/headlamp/headlamp-serviceaccount.yaml
new file mode 100644
index 000000000..2dfba7fc6
--- /dev/null
+++ b/deploy/addons/headlamp/headlamp-serviceaccount.yaml
@@ -0,0 +1,10 @@
+---
+# ServiceAccount
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: headlamp
+  namespace: headlamp
+  labels:
+    app.kubernetes.io/name: headlamp
+    app.kubernetes.io/instance: headlamp
diff --git a/pkg/addons/config.go b/pkg/addons/config.go
index 81db65789..6aba241a0 100644
--- a/pkg/addons/config.go
+++ b/pkg/addons/config.go
@@ -202,4 +202,9 @@ var Addons = []*Addon{
 		set:       SetBool,
 		callbacks: []setFn{EnableOrDisableAddon},
 	},
+	{
+		name:      "headlamp",
+		set:       SetBool,
+		callbacks: []setFn{EnableOrDisableAddon},
+	},
 }
diff --git a/pkg/minikube/assets/addons.go b/pkg/minikube/assets/addons.go
index 5b3dec96b..c7ed12843 100755
--- a/pkg/minikube/assets/addons.go
+++ b/pkg/minikube/assets/addons.go
@@ -701,6 +701,19 @@ var Addons = map[string]*Addon{
 	}, map[string]string{
 		"Helm3": "docker.io",
 	}),
+	"headlamp": NewAddon([]*BinAsset{
+		MustBinAsset(addons.HeadlampAssets, "headlamp/headlamp-namespace.yaml", vmpath.GuestAddonsDir, "headlamp-namespace.yaml", "6040"),
+		MustBinAsset(addons.HeadlampAssets, "headlamp/headlamp-service.yaml", vmpath.GuestAddonsDir, "headlamp-service.yaml", "6040"),
+		MustBinAsset(addons.HeadlampAssets, "headlamp/headlamp-deployment.yaml.tmpl", vmpath.GuestAddonsDir, "headlamp-deployment.yaml", "6040"),
+		MustBinAsset(addons.HeadlampAssets, "headlamp/headlamp-serviceaccount.yaml", vmpath.GuestAddonsDir, "headlamp-serviceaccount.yaml", "6040"),
+		MustBinAsset(addons.HeadlampAssets, "headlamp/headlamp-clusterrolebinding.yaml", vmpath.GuestAddonsDir, "headlamp-clusterrolebinding.yaml", "6040"),
+	}, false, "headlamp", "kinvolk.io", "https://minikube.sigs.k8s.io/docs/handbook/addons/headlamp/",
+		map[string]string{
+			"Headlamp": "kinvolk/headlamp:v0.9.0@sha256:465aaee6518f3fdd032965eccd6a8f49e924d144b1c86115bad613872672ec02",
+		},
+		map[string]string{
+			"Headlamp": "ghcr.io",
+		}),
 }
 
 // parseMapString creates a map based on `str` which is encoded as <key1>=<value1>,<key2>=<value2>,...
diff --git a/site/content/en/docs/handbook/addons/headlamp.md b/site/content/en/docs/handbook/addons/headlamp.md
new file mode 100644
index 000000000..f72e3aa2a
--- /dev/null
+++ b/site/content/en/docs/handbook/addons/headlamp.md
@@ -0,0 +1,51 @@
+---
+title: "Using Headlamp Addon"
+linkTitle: "Headlamp"
+weight: 1
+date: 2022-06-08
+---
+
+## Headlamp Addon
+
+[Headlamp](https://kinvolk.github.io/headlamp) is an easy-to-use and extensible Kubernetes web UI.
+
+### Enable Headlamp on minikube
+
+To enable this addon, simply run:
+```shell script
+minikube addons enable headlamp
+```
+
+Once the addon is enabled, you can access the Headlamp's web UI using the following command.
+```shell script
+minikube service headlamp -n headlamp
+```
+
+To authenticate in Headlamp, fetch the Authentication Token using the following command:
+
+```shell script
+export SECRET=$(kubectl get secrets --namespace headlamp -o custom-columns=":metadata.name" | grep "headlamp-token")
+kubectl get secret $SECRET --namespace headlamp --template=\{\{.data.token\}\} | base64 --decode
+``` 
+
+Headlamp can display more detailed information when metrics-server is installed. To install it, run:
+
+```shell script
+minikube addons enable metrics-server	
+```		
+
+### Testing installation
+
+```shell script
+kubectl get pods -n headlamp
+```
+
+If everything went well, there should be no errors about Headlamp's installation in your minikube cluster.
+
+### Disable headlamp
+
+To disable this addon, simply run:
+
+```shell script
+minikube addons disable headlamp
+```
\ No newline at end of file


Test patch:
diff --git a/cmd/minikube/cmd/config/addons_list_test.go b/cmd/minikube/cmd/config/addons_list_test.go
index ae4a53ca2..1398508c2 100644
--- a/cmd/minikube/cmd/config/addons_list_test.go
+++ b/cmd/minikube/cmd/config/addons_list_test.go
@@ -77,7 +77,7 @@ func TestAddonsList(t *testing.T) {
 			Ambassador *interface{} `json:"ambassador"`
 		}
 
-		b := make([]byte, 557)
+		b := make([]byte, 571)
 		r, w, err := os.Pipe()
 		if err != nil {
 			t.Fatalf("failed to create pipe: %v", err)
diff --git a/test/integration/addons_test.go b/test/integration/addons_test.go
index 7b85db6b3..9071afee1 100644
--- a/test/integration/addons_test.go
+++ b/test/integration/addons_test.go
@@ -95,6 +95,7 @@ func TestAddons(t *testing.T) {
 			{"HelmTiller", validateHelmTillerAddon},
 			{"Olm", validateOlmAddon},
 			{"CSI", validateCSIDriverAndSnapshots},
+			{"Headlamp", validateHeadlampAddon},
 		}
 		for _, tc := range tests {
 			tc := tc
@@ -708,3 +709,16 @@ func validateGCPAuthAddon(ctx context.Context, t *testing.T, profile string) {
 		}
 	}
 }
+
+func validateHeadlampAddon(ctx context.Context, t *testing.T, profile string) {
+	defer PostMortemLogs(t, profile)
+
+	rr, err := Run(t, exec.CommandContext(ctx, Target(), "addons", "enable", "headlamp", "-p", profile, "--alsologtostderr", "-v=1"))
+	if err != nil {
+		t.Fatalf("failed to enable headlamp addon: args: %q: %v", rr.Command(), err)
+	}
+
+	if _, err := PodWait(ctx, t, profile, "headlamp", "app.kubernetes.io/name=headlamp", Minutes(8)); err != nil {
+		t.Fatalf("failed waiting for headlamp pod: %v", err)
+	}
+}