Repository: replicatedhq/kots
Pull request #3502 (2022-12-15 17:55:30)

filter label type from side nav
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines here:
https://github.com/replicatedhq/kots/blob/main/CONTRIBUTING.md.
2. Ensure you have added appropriate tests for your PR. For more information read here:
https://github.com/replicatedhq/kots/blob/main/CONTRIBUTING.md#testing
3. If the PR is unfinished, please mark it as a draft.
-->

#### What this PR does / why we need it:
- currently showing the labels in the side nav. since labels are not configurations, it doesn't make sense for them to show up in the navigation 
<img width="740" alt="Screenshot 2022-12-15 at 11 52 38" src="https://user-images.githubusercontent.com/4998130/207932631-d02329ef-fd2e-4da4-a1d8-a6f7b41a340e.png">


#### Which issue(s) this PR fixes:

Fixes # https://app.shortcut.com/replicated/story/59046/don-t-show-labels-in-config-nav

#### Special notes for your reviewer:
<!--
Any additional special notes for your reviewer.
-->

<img width="740" alt="Screenshot 2022-12-15 at 11 52 16" src="https://user-images.githubusercontent.com/4998130/207932798-f5a801d7-a9df-4c2a-985c-99bbb86d2f16.png">


## Steps to reproduce
<!---
Please provide minimum instructions for how someone can view/test/verify your changes.
-->

#### Does this PR introduce a user-facing change?
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
-->
```release-note
- Config Page: fixes an issue where field labels were rendered in the config page side nav
```

#### Does this PR require documentation?
<!--
If no, just write "NONE" below.
If yes, link to the related https://github.com/replicatedhq/kots.io documentation PR:
-->
none 



Patch:
diff --git a/pkg/kotsadm/rqlite.go b/pkg/kotsadm/rqlite.go
index a87dda308..a306c7f7a 100644
--- a/pkg/kotsadm/rqlite.go
+++ b/pkg/kotsadm/rqlite.go
@@ -46,7 +46,7 @@ func getRqliteYAML(deployOptions types.DeployOptions) (map[string][]byte, error)
 	docs["rqlite-service.yaml"] = service.Bytes()
 
 	var headlessService bytes.Buffer
-	if err := s.Encode(kotsadmobjects.RqliteHeadlessService(deployOptions.Namespace), &service); err != nil {
+	if err := s.Encode(kotsadmobjects.RqliteHeadlessService(deployOptions.Namespace), &headlessService); err != nil {
 		return nil, errors.Wrap(err, "failed to marshal rqlite headless service")
 	}
 	docs["rqlite-headless-service.yaml"] = headlessService.Bytes()
diff --git a/pkg/template/static_context.go b/pkg/template/static_context.go
index c9fbe8aa9..30a7bc652 100644
--- a/pkg/template/static_context.go
+++ b/pkg/template/static_context.go
@@ -35,6 +35,7 @@ import (
 	"gopkg.in/yaml.v3"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	k8sversion "k8s.io/apimachinery/pkg/version"
 	"k8s.io/client-go/kubernetes"
 	certUtil "k8s.io/client-go/util/cert"
 )
@@ -44,6 +45,8 @@ type Ctx interface {
 }
 
 type StaticCtx struct {
+	// a new clientset will be initialized if nil
+	clientset kubernetes.Interface
 }
 
 type TLSPair struct {
@@ -100,6 +103,10 @@ func (ctx StaticCtx) FuncMap() template.FuncMap {
 
 	funcMap["YamlEscape"] = ctx.yamlEscape
 
+	funcMap["KubernetesVersion"] = ctx.kubernetesVersion
+	funcMap["KubernetesMajorVersion"] = ctx.kubernetesMajorVersion
+	funcMap["KubernetesMinorVersion"] = ctx.kubernetesMinorVersion
+
 	return funcMap
 }
 
@@ -525,7 +532,7 @@ func getNodes(clientset kubernetes.Interface) ([]corev1.Node, error) {
 }
 
 func (ctx StaticCtx) distribution() string {
-	clientset, err := k8sutil.GetClientset()
+	clientset, err := ctx.getClientset()
 	if err != nil {
 		return ""
 	}
@@ -546,7 +553,7 @@ func (ctx StaticCtx) distribution() string {
 }
 
 func (ctx StaticCtx) nodeCount() int {
-	clientset, err := k8sutil.GetClientset()
+	clientset, err := ctx.getClientset()
 	if err != nil {
 		return 0
 	}
@@ -584,6 +591,61 @@ func (ctx StaticCtx) yamlEscape(plain string) string {
 	return indented
 }
 
+func (ctx StaticCtx) kubernetesVersion() string {
+	clientset, err := ctx.getClientset()
+	if err != nil {
+		return ""
+	}
+	sv, err := getK8sServerVersion(clientset)
+	if err != nil {
+		return ""
+	}
+	return strings.TrimPrefix(sv.GitVersion, "v")
+}
+
+func (ctx StaticCtx) kubernetesMajorVersion() string {
+	clientset, err := ctx.getClientset()
+	if err != nil {
+		return ""
+	}
+	sv, err := getK8sServerVersion(clientset)
+	if err != nil {
+		return ""
+	}
+	return sv.Major
+}
+
+func (ctx StaticCtx) kubernetesMinorVersion() string {
+	clientset, err := ctx.getClientset()
+	if err != nil {
+		return ""
+	}
+	sv, err := getK8sServerVersion(clientset)
+	if err != nil {
+		return ""
+	}
+	return sv.Minor
+}
+
+func getK8sServerVersion(clientset kubernetes.Interface) (*k8sversion.Info, error) {
+	sv, err := clientset.Discovery().ServerVersion()
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to get kubernetes server version")
+	}
+	return sv, nil
+}
+
+func (ctx StaticCtx) getClientset() (kubernetes.Interface, error) {
+	if ctx.clientset != nil {
+		return ctx.clientset, nil
+	}
+	clientset, err := k8sutil.GetClientset()
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to get kubernetes clientset")
+	}
+	return clientset, nil
+}
+
 // copied from sprig
 func indent(spaces int, v string) string {
 	pad := strings.Repeat(" ", spaces)
diff --git a/web/src/features/AppConfig/components/AppConfig.tsx b/web/src/features/AppConfig/components/AppConfig.tsx
index 7ca926a6b..b2be543b6 100644
--- a/web/src/features/AppConfig/components/AppConfig.tsx
+++ b/web/src/features/AppConfig/components/AppConfig.tsx
@@ -629,23 +629,27 @@ class AppConfig extends Component<Props, State> {
                   </div>
                   {group.items ? (
                     <div className="side-nav-items">
-                      {group.items?.map((item, j) => {
-                        const hash = this.props.location.hash.slice(1);
-                        if (item.hidden || item.when === "false") {
-                          return;
-                        }
-                        return (
-                          <a
-                            className={`u-fontSize--normal u-lineHeight--normal ${
-                              hash === `${item.name}-group` ? "active-item" : ""
-                            }`}
-                            href={`#${item.name}-group`}
-                            key={`${j}-${item.name}-${item.title}`}
-                          >
-                            {item.title}
-                          </a>
-                        );
-                      })}
+                      {group.items
+                        ?.filter((item) => item.type !== "label")
+                        ?.map((item, j) => {
+                          const hash = this.props.location.hash.slice(1);
+                          if (item.hidden || item.when === "false") {
+                            return;
+                          }
+                          return (
+                            <a
+                              className={`u-fontSize--normal u-lineHeight--normal ${
+                                hash === `${item.name}-group`
+                                  ? "active-item"
+                                  : ""
+                              }`}
+                              href={`#${item.name}-group`}
+                              key={`${j}-${item.name}-${item.title}`}
+                            >
+                              {item.title}
+                            </a>
+                          );
+                        })}
                     </div>
                   ) : null}
                 </div>


Test patch:
diff --git a/pkg/kotsadm/rqlite_test.go b/pkg/kotsadm/rqlite_test.go
index b3835549e..d6b6714c0 100644
--- a/pkg/kotsadm/rqlite_test.go
+++ b/pkg/kotsadm/rqlite_test.go
@@ -54,9 +54,18 @@ func Test_getRqliteYAML(t *testing.T) {
 			req.NoError(err)
 			service := obj.(*corev1.Service)
 
+			headlessServiceManifest, ok := manifests["rqlite-headless-service.yaml"]
+			assert.Equal(t, true, ok)
+			obj, _, err = decode(headlessServiceManifest, nil, nil)
+			req.NoError(err)
+			headlessService := obj.(*corev1.Service)
+
 			assert.Len(t, statefulSet.Spec.VolumeClaimTemplates, 1)
 
 			assert.Equal(t, service.Spec.Type, corev1.ServiceTypeClusterIP)
+
+			assert.Equal(t, headlessService.Spec.Type, corev1.ServiceTypeClusterIP)
+			assert.Equal(t, headlessService.Spec.ClusterIP, corev1.ClusterIPNone)
 		})
 	}
 }
diff --git a/pkg/template/static_context_test.go b/pkg/template/static_context_test.go
index 1872ae152..12f1f9fab 100644
--- a/pkg/template/static_context_test.go
+++ b/pkg/template/static_context_test.go
@@ -4,10 +4,14 @@ import (
 	"crypto/x509"
 	"encoding/pem"
 	"fmt"
+	"strings"
 	"testing"
 
 	"github.com/stretchr/testify/require"
 	"gopkg.in/yaml.v2"
+	"k8s.io/apimachinery/pkg/version"
+	fakediscovery "k8s.io/client-go/discovery/fake"
+	fakeclientset "k8s.io/client-go/kubernetes/fake"
 )
 
 func TestStaticContext_kubeSeal_badCert(t *testing.T) {
@@ -212,3 +216,38 @@ func TestProxyEnvVars(t *testing.T) {
 	req.Equal(httpProxy, "2.2.2.2")
 	req.Equal(noProxy, "3.3.3.3")
 }
+
+func TestKubernetesVersion(t *testing.T) {
+	clientset := fakeclientset.NewSimpleClientset()
+	fakeDiscovery, ok := clientset.Discovery().(*fakediscovery.FakeDiscovery)
+	if !ok {
+		t.Error("couldn't convert Discovery() to *FakeDiscovery")
+		return
+	}
+
+	wantK8sVersion := "v1.25.0"
+	wantK8sMajorVersion := "1"
+	wantK8sMinorVersion := "25"
+
+	fakeDiscovery.FakedServerVersion = &version.Info{
+		GitVersion: wantK8sVersion,
+		Major:      wantK8sMajorVersion,
+		Minor:      wantK8sMinorVersion,
+	}
+
+	ctx := StaticCtx{
+		clientset: clientset,
+	}
+
+	if actualK8sVersion := ctx.kubernetesVersion(); actualK8sVersion != strings.TrimPrefix(wantK8sVersion, "v") {
+		t.Errorf("expected kubernetes version to be %q, got %q", strings.TrimPrefix(wantK8sVersion, "v"), actualK8sVersion)
+	}
+
+	if actualK8sMajorVersion := ctx.kubernetesMajorVersion(); actualK8sMajorVersion != wantK8sMajorVersion {
+		t.Errorf("expected kubernetes major version to be %q, got %q", wantK8sMajorVersion, actualK8sMajorVersion)
+	}
+
+	if actualK8sMinorVersion := ctx.kubernetesMinorVersion(); actualK8sMinorVersion != wantK8sMinorVersion {
+		t.Errorf("expected kubernetes minor version to be %q, got %q", wantK8sMinorVersion, actualK8sMinorVersion)
+	}
+}