cybozu-go / accurate

Kubernetes controller for multi-tenancy. It propagates resources between namespaces accurately and allows tenant users to create/delete sub-namespaces.
https://cybozu-go.github.io/accurate/
Apache License 2.0
38 stars 5 forks source link

Add Helm chart #11

Closed d-kuro closed 2 years ago

d-kuro commented 3 years ago

refs: https://github.com/cybozu-go/accurate/issues/10

Review Points

TODOs

Diffs

```text === RUN TestChart === RUN TestChart/namespace/accurate chart_test.go:54: object was not found: not found [namespace/accurate] === RUN TestChart/customresourcedefinition.apiextensions.k8s.io/subnamespaces.accurate.cybozu.com === RUN TestChart/serviceaccount/accurate/accurate-controller-manager === RUN TestChart/role.rbac.authorization.k8s.io/accurate/accurate-leader-election-role === RUN TestChart/clusterrole.rbac.authorization.k8s.io/accurate-manager-role === RUN TestChart/clusterrole.rbac.authorization.k8s.io/accurate-subnamespace-editor-role === RUN TestChart/clusterrole.rbac.authorization.k8s.io/accurate-subnamespace-viewer-role === RUN TestChart/rolebinding.rbac.authorization.k8s.io/accurate/accurate-leader-election-rolebinding === RUN TestChart/clusterrolebinding.rbac.authorization.k8s.io/accurate-manager-admin === RUN TestChart/clusterrolebinding.rbac.authorization.k8s.io/accurate-manager-rolebinding === RUN TestChart/configmap/accurate/accurate-config-6tkg9g6bm6 chart_test.go:54: configmap/accurate/accurate-config mismatch (-want +got):   &v1.ConfigMap{    TypeMeta: {Kind: "ConfigMap", APIVersion: "v1"},    ObjectMeta: {Name: "accurate-config", Namespace: "accurate"},    Immutable: nil, -  Data: map[string]string{ -  "config.yaml": ( -  """ -  # Labels to be propagated to sub-namespaces. -  # It is also possible to specify a glob pattern that can be interpreted by Go's "path.Match" func. -  # https://pkg.go.dev/path#Match -  labelKeys: -  - team -  -  # Annotations to be propagated to sub-namespaces. -  # It is also possible to specify a glob pattern that can be interpreted by Go's "path.Match" func. -  # https://pkg.go.dev/path#Match -  annotationKeys: -  # An example to propagate an annotation for MetalLB -  # https://metallb.universe.tf/usage/#requesting-specific-ips -  - metallb.universe.tf/address-pool -  -  # List of GVK for namespace-scoped resources that can be propagated. -  # Any namespace-scoped resource is allowed. -  watches: -  - group: rbac.authorization.k8s.io -  version: v1 -  kind: Role -  - group: rbac.authorization.k8s.io -  version: v1 -  kind: RoleBinding -  - version: v1 -  kind: Secret -  """ -  ), -  }, +  Data: map[string]string{ +  "config.yaml": ( +  """ +  watches: +  - group: rbac.authorization.k8s.io +  kind: Role +  version: v1 +  - group: rbac.authorization.k8s.io +  kind: RoleBinding +  version: v1 +  - kind: Secret +  version: v1 +  """ +  ), +  },    BinaryData: nil,   } === RUN TestChart/service/accurate/accurate-webhook-service === RUN TestChart/deployment.apps/accurate/accurate-controller-manager chart_test.go:54: deployment.apps/accurate/accurate-controller-manager mismatch (-want +got):   &v1.Deployment{    TypeMeta: {Kind: "Deployment", APIVersion: "apps/v1"},    ObjectMeta: {Name: "accurate-controller-manager", Namespace: "accurate"},    Spec: v1.DeploymentSpec{    Replicas: &2,    Selector: &{MatchLabels: {"app.kubernetes.io/component": "controller", "app.kubernetes.io/name": "accurate"}},    Template: v1.PodTemplateSpec{    ObjectMeta: v1.ObjectMeta{    ... // 9 identical fields    DeletionGracePeriodSeconds: nil,    Labels: {"app.kubernetes.io/component": "controller", "app.kubernetes.io/name": "accurate"}, -  Annotations: nil, +  Annotations: map[string]string{ +  "checksum/config": "c63a34726123e77a197a658c7d16af9ef6428654dc5fad90326d3a1c07091e5d", +  },    OwnerReferences: nil,    Finalizers: nil,    ... // 2 identical fields    },    Spec: v1.PodSpec{    Volumes: []v1.Volume{    {Name: "cert", VolumeSource: {Secret: &{SecretName: "webhook-server-cert", DefaultMode: &420}}},    {    Name: "config",    VolumeSource: v1.VolumeSource{    ... // 16 identical fields    FC: nil,    AzureFile: nil,    ConfigMap: &v1.ConfigMapVolumeSource{ -  LocalObjectReference: v1.LocalObjectReference{Name: "accurate-config-6tkg9g6bm6"}, +  LocalObjectReference: v1.LocalObjectReference{Name: "accurate-config"},    Items: nil,    DefaultMode: nil,    Optional: nil,    },    VsphereVolume: nil,    Quobyte: nil,    ... // 8 identical fields    },    },    },    InitContainers: nil,    Containers: {{Name: "manager", Image: "ghcr.io/cybozu-go/accurate:0.1.0", Ports: {{Name: "webhook-server", ContainerPort: 9443, Protocol: "TCP"}, {Name: "health", ContainerPort: 8081, Protocol: "TCP"}, {Name: "metrics", ContainerPort: 8080, Protocol: "TCP"}}, Env: {{Name: "POD_NAMESPACE", ValueFrom: &{FieldRef: &{FieldPath: "metadata.namespace"}}}}, ...}},    ... // 32 identical fields    },    },    Strategy: {},    MinReadySeconds: 0,    ... // 3 identical fields    },    Status: {},   } === RUN TestChart/certificate.cert-manager.io/accurate/accurate-serving-cert === RUN TestChart/issuer.cert-manager.io/accurate/accurate-selfsigned-issuer === RUN TestChart/mutatingwebhookconfiguration.admissionregistration.k8s.io/accurate-mutating-webhook-configuration === RUN TestChart/validatingwebhookconfiguration.admissionregistration.k8s.io/accurate-validating-webhook-configuration --- FAIL: TestChart (0.02s) --- FAIL: TestChart/namespace/accurate (0.00s) --- PASS: TestChart/customresourcedefinition.apiextensions.k8s.io/subnamespaces.accurate.cybozu.com (0.00s) --- PASS: TestChart/serviceaccount/accurate/accurate-controller-manager (0.00s) --- PASS: TestChart/role.rbac.authorization.k8s.io/accurate/accurate-leader-election-role (0.00s) --- PASS: TestChart/clusterrole.rbac.authorization.k8s.io/accurate-manager-role (0.00s) --- PASS: TestChart/clusterrole.rbac.authorization.k8s.io/accurate-subnamespace-editor-role (0.00s) --- PASS: TestChart/clusterrole.rbac.authorization.k8s.io/accurate-subnamespace-viewer-role (0.00s) --- PASS: TestChart/rolebinding.rbac.authorization.k8s.io/accurate/accurate-leader-election-rolebinding (0.00s) --- PASS: TestChart/clusterrolebinding.rbac.authorization.k8s.io/accurate-manager-admin (0.00s) --- PASS: TestChart/clusterrolebinding.rbac.authorization.k8s.io/accurate-manager-rolebinding (0.00s) --- FAIL: TestChart/configmap/accurate/accurate-config-6tkg9g6bm6 (0.00s) --- PASS: TestChart/service/accurate/accurate-webhook-service (0.00s) --- FAIL: TestChart/deployment.apps/accurate/accurate-controller-manager (0.00s) --- PASS: TestChart/certificate.cert-manager.io/accurate/accurate-serving-cert (0.00s) --- PASS: TestChart/issuer.cert-manager.io/accurate/accurate-selfsigned-issuer (0.00s) --- PASS: TestChart/mutatingwebhookconfiguration.admissionregistration.k8s.io/accurate-mutating-webhook-configuration (0.00s) --- PASS: TestChart/validatingwebhookconfiguration.admissionregistration.k8s.io/accurate-validating-webhook-configuration (0.00s) FAIL FAIL tests 0.467s FAIL ```
d-kuro commented 2 years ago

@ymmt2005 @zoetrope

I fixed the pull request.

Review Poinsts:

d-kuro commented 2 years ago

@ymmt2005

Then, users cannot stop creating a ServiceAccount, right?

Is there a case where a User wants to stop creating a ServiceAccount? I didn't understand why it was a problem to have to create a ServiceAccount.

So, if pullPolicy is not set, this would render as follows, right?

No, if the field is empty the with block will not be rendered.

Rendering with the default values will result in the following YAML:

helm template -n accurate accurate ./charts/accurate
<snip>
# Source: accurate/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: accurate-controller-manager
  namespace: accurate
  labels:
    app.kubernetes.io/component: controller
    helm.sh/chart: accurate-0.1.0
    app.kubernetes.io/name: accurate
    app.kubernetes.io/version: "0.1.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/component: controller
  template:
    metadata:
      annotations:
        checksum/config: 856d9f37889d4ef4ad9a5bbec38b558ab0e1c5db0dac189d4e9aceadf52be133
      labels:
        app.kubernetes.io/component: controller
    spec:
      containers:
        - name: manager
          image: "ghcr.io/cybozu-go/accurate:0.1.0"
          ports:
            - containerPort: 9443
              name: webhook-server
              protocol: TCP
            - containerPort: 8081
              name: health
              protocol: TCP
            - containerPort: 8080
              name: metrics
              protocol: TCP
          resources:
            requests:
              cpu: 100m
              memory: 20Mi
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
          env:
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          livenessProbe:
            httpGet:
              path: /healthz
              port: health
            initialDelaySeconds: 15
            periodSeconds: 20
          readinessProbe:
            httpGet:
              path: /readyz
              port: health
            initialDelaySeconds: 5
            periodSeconds: 10
          volumeMounts:
            - mountPath: /tmp/k8s-webhook-server/serving-certs
              name: cert
              readOnly: true
            - mountPath: /etc/accurate
              name: config
      securityContext:
        runAsNonRoot: true
      serviceAccountName: accurate-controller-manager
      terminationGracePeriodSeconds: 10
      volumes:
        - name: cert
          secret:
            defaultMode: 420
            secretName: webhook-server-cert
        - configMap:
            name: accurate-config
          name: config
<snip>
ymmt2005 commented 2 years ago

@d-kuro

Is there a case where a user wants to stop creating a ServiceAccount? I didn't understand why it was a problem to have to create a ServiceAccount.

I don't think users want to avoid creating a ServiceAccount, but my point is that even when a user chooses not to create a ServiceAccount, the Helm template should generate a valid manifest. Currently, it does not seem so.

I'd like either one of the following:

No, if the field is empty the with block will not be rendered.

I see. Thank you.

d-kuro commented 2 years ago

@ymmt2005

I see, thank you for comments.

I don't think users want to avoid creating a ServiceAccount, but my point is that even when a user chooses not to create a ServiceAccount, the Helm template should generate a valid manifest. Currently, it does not seem so.

I'd like either one of the following:

  • Users cannot avoid creating a ServiceAccount, or
  • Helm can generate a valid manifest if a user chooses not to create a ServiceAccount

In the _helpers.tpl file, there was a flag whether or not to create a ServiceAccount, which was automatically created by the helm init command.

{{- if .Values.serviceAccount.create }}

This is no longer in use and has been removed in the following commit:

https://github.com/cybozu-go/accurate/pull/11/commits/ded45226cf14d1d48183eb36c8cab19e5540634d

So a ServiceAccount is always created.

ymmt2005 commented 2 years ago

Great!

d-kuro commented 2 years ago

Difference from kustomize

    --- FAIL: TestHelmCharts/namespace/accurate (0.00s)
        chart_test.go:51: object was not found: not found [namespace/accurate]
    --- FAIL: TestHelmCharts/serviceaccount/accurate/accurate-controller-manager (0.00s)
        chart_test.go:51: serviceaccount/accurate/accurate-controller-manager mismatch (-want +got):
              &v1.ServiceAccount{
                TypeMeta: {Kind: "ServiceAccount", APIVersion: "v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Secrets:                      nil,
                ImagePullSecrets:             nil,
                AutomountServiceAccountToken: nil,
              }
    --- FAIL: TestHelmCharts/role.rbac.authorization.k8s.io/accurate/accurate-leader-election-role (0.00s)
        chart_test.go:51: role.rbac.authorization.k8s.io/accurate/accurate-leader-election-role mismatch (-want +got):
              &v1.Role{
                TypeMeta: {Kind: "Role", APIVersion: "rbac.authorization.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Rules: {{Verbs: {"get", "list", "watch", "create", ...}, APIGroups: {""}, Resources: {"configmaps"}}, {Verbs: {"get", "list", "watch", "create", ...}, APIGroups: {"coordination.k8s.io"}, Resources: {"leases"}}, {Verbs: {"create", "patch"}, APIGroups: {""}, Resources: {"events"}}},
              }
    --- FAIL: TestHelmCharts/clusterrole.rbac.authorization.k8s.io/accurate-manager-role (0.00s)
        chart_test.go:51: clusterrole.rbac.authorization.k8s.io/accurate-manager-role mismatch (-want +got):
              &v1.ClusterRole{
                TypeMeta: {Kind: "ClusterRole", APIVersion: "rbac.authorization.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Rules:           {{Verbs: {"create", "delete", "get", "list", ...}, APIGroups: {""}, Resources: {"namespaces"}}, {Verbs: {"create", "delete", "get", "list", ...}, APIGroups: {"accurate.cybozu.com"}, Resources: {"subnamespaces"}}, {Verbs: {"update"}, APIGroups: {"accurate.cybozu.com"}, Resources: {"subnamespaces/finalizers"}}, {Verbs: {"get", "patch", "update"}, APIGroups: {"accurate.cybozu.com"}, Resources: {"subnamespaces/status"}}},
                AggregationRule: nil,
              }
    --- FAIL: TestHelmCharts/clusterrole.rbac.authorization.k8s.io/accurate-subnamespace-editor-role (0.00s)
        chart_test.go:51: clusterrole.rbac.authorization.k8s.io/accurate-subnamespace-editor-role mismatch (-want +got):
              &v1.ClusterRole{
                TypeMeta: {Kind: "ClusterRole", APIVersion: "rbac.authorization.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by":                 "Helm",
                        "app.kubernetes.io/name":                       "accurate",
            +           "app.kubernetes.io/version":                    "0.1.0",
            +           "helm.sh/chart":                                "accurate-0.1.0",
                        "rbac.authorization.k8s.io/aggregate-to-admin": "true",
                        "rbac.authorization.k8s.io/aggregate-to-edit":  "true",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Rules:           {{Verbs: {"create", "delete", "get", "list", ...}, APIGroups: {"accurate.cybozu.com"}, Resources: {"subnamespaces"}}, {Verbs: {"get"}, APIGroups: {"accurate.cybozu.com"}, Resources: {"subnamespaces/status"}}},
                AggregationRule: nil,
              }
    --- FAIL: TestHelmCharts/clusterrole.rbac.authorization.k8s.io/accurate-subnamespace-viewer-role (0.00s)
        chart_test.go:51: clusterrole.rbac.authorization.k8s.io/accurate-subnamespace-viewer-role mismatch (-want +got):
              &v1.ClusterRole{
                TypeMeta: {Kind: "ClusterRole", APIVersion: "rbac.authorization.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by":                "Helm",
                        "app.kubernetes.io/name":                      "accurate",
            +           "app.kubernetes.io/version":                   "0.1.0",
            +           "helm.sh/chart":                               "accurate-0.1.0",
                        "rbac.authorization.k8s.io/aggregate-to-view": "true",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Rules:           {{Verbs: {"get", "list", "watch"}, APIGroups: {"accurate.cybozu.com"}, Resources: {"subnamespaces"}}, {Verbs: {"get"}, APIGroups: {"accurate.cybozu.com"}, Resources: {"subnamespaces/status"}}},
                AggregationRule: nil,
              }
    --- FAIL: TestHelmCharts/rolebinding.rbac.authorization.k8s.io/accurate/accurate-leader-election-rolebinding (0.00s)
        chart_test.go:51: rolebinding.rbac.authorization.k8s.io/accurate/accurate-leader-election-rolebinding mismatch (-want +got):
              &v1.RoleBinding{
                TypeMeta: {Kind: "RoleBinding", APIVersion: "rbac.authorization.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Subjects: {{Kind: "ServiceAccount", Name: "accurate-controller-manager", Namespace: "accurate"}},
                RoleRef:  {APIGroup: "rbac.authorization.k8s.io", Kind: "Role", Name: "accurate-leader-election-role"},
              }
    --- FAIL: TestHelmCharts/clusterrolebinding.rbac.authorization.k8s.io/accurate-manager-admin (0.00s)
        chart_test.go:51: clusterrolebinding.rbac.authorization.k8s.io/accurate-manager-admin mismatch (-want +got):
              &v1.ClusterRoleBinding{
                TypeMeta: {Kind: "ClusterRoleBinding", APIVersion: "rbac.authorization.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Subjects: {{Kind: "ServiceAccount", Name: "accurate-controller-manager", Namespace: "accurate"}},
                RoleRef:  {APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", Name: "admin"},
              }
    --- FAIL: TestHelmCharts/clusterrolebinding.rbac.authorization.k8s.io/accurate-manager-rolebinding (0.00s)
        chart_test.go:51: clusterrolebinding.rbac.authorization.k8s.io/accurate-manager-rolebinding mismatch (-want +got):
              &v1.ClusterRoleBinding{
                TypeMeta: {Kind: "ClusterRoleBinding", APIVersion: "rbac.authorization.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Subjects: {{Kind: "ServiceAccount", Name: "accurate-controller-manager", Namespace: "accurate"}},
                RoleRef:  {APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", Name: "accurate-manager-role"},
              }
    --- FAIL: TestHelmCharts/configmap/accurate/accurate-config-6tkg9g6bm6 (0.00s)
        chart_test.go:51: configmap/accurate/accurate-config mismatch (-want +got):
              &v1.ConfigMap{
                TypeMeta: {Kind: "ConfigMap", APIVersion: "v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
            -       Labels:                     nil,
            +       Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
            +           "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
            +       },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Immutable: nil,
            -   Data: map[string]string{
            -       "config.yaml": (
            -           """
            -           # Labels to be propagated to sub-namespaces.
            -           # It is also possible to specify a glob pattern that can be interpreted by Go's "path.Match" func.
            -           # https://pkg.go.dev/path#Match
            -           labelKeys:
            -           - team
            -           
            -           # Annotations to be propagated to sub-namespaces.
            -           # It is also possible to specify a glob pattern that can be interpreted by Go's "path.Match" func.
            -           # https://pkg.go.dev/path#Match
            -           annotationKeys:
            -           # An example to propagate an annotation for MetalLB
            -           # https://metallb.universe.tf/usage/#requesting-specific-ips
            -           - metallb.universe.tf/address-pool
            -           
            -           # List of GVK for namespace-scoped resources that can be propagated.
            -           # Any namespace-scoped resource is allowed.
            -           watches:
            -           - group: rbac.authorization.k8s.io
            -             version: v1
            -             kind: Role
            -           - group: rbac.authorization.k8s.io
            -             version: v1
            -             kind: RoleBinding
            -           - version: v1
            -             kind: Secret
            -           """
            -       ),
            -   },
            +   Data: map[string]string{
            +       "config.yaml": (
            +           """
            +           watches: 
            +             - group: rbac.authorization.k8s.io
            +               kind: Role
            +               version: v1
            +             - group: rbac.authorization.k8s.io
            +               kind: RoleBinding
            +               version: v1
            +             - kind: Secret
            +               version: v1
            +           """
            +       ),
            +   },
                BinaryData: nil,
              }
    --- FAIL: TestHelmCharts/service/accurate/accurate-webhook-service (0.00s)
        chart_test.go:51: service/accurate/accurate-webhook-service mismatch (-want +got):
              &v1.Service{
                TypeMeta: {Kind: "Service", APIVersion: "v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Spec:   {Ports: {{Port: 443, TargetPort: {Type: 1, StrVal: "webhook-server"}}}, Selector: {"app.kubernetes.io/component": "controller", "app.kubernetes.io/name": "accurate"}},
                Status: {},
              }
    --- FAIL: TestHelmCharts/deployment.apps/accurate/accurate-controller-manager (0.00s)
        chart_test.go:51: deployment.apps/accurate/accurate-controller-manager mismatch (-want +got):
              &v1.Deployment{
                TypeMeta: {Kind: "Deployment", APIVersion: "apps/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
                        "app.kubernetes.io/component":  "controller",
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     nil,
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Spec: v1.DeploymentSpec{
                    Replicas: &2,
                    Selector: &{MatchLabels: {"app.kubernetes.io/component": "controller", "app.kubernetes.io/name": "accurate"}},
                    Template: v1.PodTemplateSpec{
                        ObjectMeta: v1.ObjectMeta{
                            ... // 9 identical fields
                            DeletionGracePeriodSeconds: nil,
                            Labels:                     {"app.kubernetes.io/component": "controller", "app.kubernetes.io/name": "accurate"},
            -               Annotations:                nil,
            +               Annotations: map[string]string{
            +                   "checksum/config": "856d9f37889d4ef4ad9a5bbec38b558ab0e1c5db0dac189d4e9aceadf52be133",
            +               },
                            OwnerReferences: nil,
                            Finalizers:      nil,
                            ... // 2 identical fields
                        },
                        Spec: v1.PodSpec{
                            Volumes: []v1.Volume{
                                {Name: "cert", VolumeSource: {Secret: &{SecretName: "webhook-server-cert", DefaultMode: &420}}},
                                {
                                    Name: "config",
                                    VolumeSource: v1.VolumeSource{
                                        ... // 16 identical fields
                                        FC:        nil,
                                        AzureFile: nil,
                                        ConfigMap: &v1.ConfigMapVolumeSource{
            -                               LocalObjectReference: v1.LocalObjectReference{Name: "accurate-config-6tkg9g6bm6"},
            +                               LocalObjectReference: v1.LocalObjectReference{Name: "accurate-config"},
                                            Items:                nil,
                                            DefaultMode:          nil,
                                            Optional:             nil,
                                        },
                                        VsphereVolume: nil,
                                        Quobyte:       nil,
                                        ... // 8 identical fields
                                    },
                                },
                            },
                            InitContainers: nil,
                            Containers:     {{Name: "manager", Image: "ghcr.io/cybozu-go/accurate:0.1.0", Ports: {{Name: "webhook-server", ContainerPort: 9443, Protocol: "TCP"}, {Name: "health", ContainerPort: 8081, Protocol: "TCP"}, {Name: "metrics", ContainerPort: 8080, Protocol: "TCP"}}, Env: {{Name: "POD_NAMESPACE", ValueFrom: &{FieldRef: &{FieldPath: "metadata.namespace"}}}}, ...}},
                            ... // 32 identical fields
                        },
                    },
                    Strategy:        {},
                    MinReadySeconds: 0,
                    ... // 3 identical fields
                },
                Status: {},
              }
    --- FAIL: TestHelmCharts/certificate.cert-manager.io/accurate/accurate-serving-cert (0.00s)
        chart_test.go:51: certificate.cert-manager.io/accurate/accurate-serving-cert mismatch (-want +got):
              &unstructured.Unstructured{
                Object: map[string]interface{}{
                    "apiVersion": string("cert-manager.io/v1"),
                    "kind":       string("Certificate"),
                    "metadata": map[string]interface{}{
                        "labels": map[string]interface{}{
            +               "app.kubernetes.io/managed-by": string("Helm"),
                            "app.kubernetes.io/name":       string("accurate"),
            +               "app.kubernetes.io/version":    string("0.1.0"),
            +               "helm.sh/chart":                string("accurate-0.1.0"),
                        },
                        "name":      string("accurate-serving-cert"),
                        "namespace": string("accurate"),
                    },
                    "spec": map[string]interface{}{"dnsNames": []interface{}{string("accurate-webhook-service.accurate.svc"), string("accurate-webhook-service.accurate.svc.cluster.local")}, "issuerRef": map[string]interface{}{"kind": string("Issuer"), "name": string("accurate-selfsigned-issuer")}, "secretName": string("webhook-server-cert")},
                },
              }
    --- FAIL: TestHelmCharts/issuer.cert-manager.io/accurate/accurate-selfsigned-issuer (0.00s)
        chart_test.go:51: issuer.cert-manager.io/accurate/accurate-selfsigned-issuer mismatch (-want +got):
              &unstructured.Unstructured{
                Object: map[string]interface{}{
                    "apiVersion": string("cert-manager.io/v1"),
                    "kind":       string("Issuer"),
                    "metadata": map[string]interface{}{
                        "labels": map[string]interface{}{
            +               "app.kubernetes.io/managed-by": string("Helm"),
                            "app.kubernetes.io/name":       string("accurate"),
            +               "app.kubernetes.io/version":    string("0.1.0"),
            +               "helm.sh/chart":                string("accurate-0.1.0"),
                        },
                        "name":      string("accurate-selfsigned-issuer"),
                        "namespace": string("accurate"),
                    },
                    "spec": map[string]interface{}{"selfSigned": map[string]interface{}{}},
                },
              }
    --- FAIL: TestHelmCharts/mutatingwebhookconfiguration.admissionregistration.k8s.io/accurate-mutating-webhook-configuration (0.00s)
        chart_test.go:51: mutatingwebhookconfiguration.admissionregistration.k8s.io/accurate-mutating-webhook-configuration mismatch (-want +got):
              &v1.MutatingWebhookConfiguration{
                TypeMeta: {Kind: "MutatingWebhookConfiguration", APIVersion: "admissionregistration.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     {"cert-manager.io/inject-ca-from": "accurate/accurate-serving-cert"},
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Webhooks: {{Name: "msubnamespace.kb.io", ClientConfig: {Service: &{Namespace: "accurate", Name: "accurate-webhook-service", Path: &"/mutate-accurate-cybozu-com-v1-subnamespace"}}, Rules: {{Operations: {"CREATE", "UPDATE"}, Rule: {APIGroups: {"accurate.cybozu.com"}, APIVersions: {"v1"}, Resources: {"subnamespaces"}}}}, FailurePolicy: &"Fail", ...}},
              }
    --- FAIL: TestHelmCharts/validatingwebhookconfiguration.admissionregistration.k8s.io/accurate-validating-webhook-configuration (0.00s)
        chart_test.go:51: validatingwebhookconfiguration.admissionregistration.k8s.io/accurate-validating-webhook-configuration mismatch (-want +got):
              &v1.ValidatingWebhookConfiguration{
                TypeMeta: {Kind: "ValidatingWebhookConfiguration", APIVersion: "admissionregistration.k8s.io/v1"},
                ObjectMeta: v1.ObjectMeta{
                    ... // 8 identical fields
                    DeletionTimestamp:          nil,
                    DeletionGracePeriodSeconds: nil,
                    Labels: map[string]string{
            +           "app.kubernetes.io/managed-by": "Helm",
                        "app.kubernetes.io/name":       "accurate",
            +           "app.kubernetes.io/version":    "0.1.0",
            +           "helm.sh/chart":                "accurate-0.1.0",
                    },
                    Annotations:     {"cert-manager.io/inject-ca-from": "accurate/accurate-serving-cert"},
                    OwnerReferences: nil,
                    ... // 3 identical fields
                },
                Webhooks: {{Name: "vnamespace.kb.io", ClientConfig: {Service: &{Namespace: "accurate", Name: "accurate-webhook-service", Path: &"/validate-v1-namespace"}}, Rules: {{Operations: {"CREATE", "UPDATE", "DELETE"}, Rule: {APIGroups: {""}, APIVersions: {"v1"}, Resources: {"namespaces"}}}}, FailurePolicy: &"Fail", ...}, {Name: "vsubnamespace.kb.io", ClientConfig: {Service: &{Namespace: "accurate", Name: "accurate-webhook-service", Path: &"/validate-accurate-cybozu-com-v1-subnamespace"}}, Rules: {{Operations: {"CREATE", "UPDATE"}, Rule: {APIGroups: {"accurate.cybozu.com"}, APIVersions: {"v1"}, Resources: {"subnamespaces"}}}}, FailurePolicy: &"Fail", ...}},
              }
FAIL
FAIL    tests   0.745s
FAIL

Test codes

```concole $ pwd /path/to/dir/github.com/cybozu-go/accurate $ kustomize build . > ./charts/tests/testdata/kustomize.yaml ``` ```go package tests import ( "os" "path/filepath" "strings" "testing" "github.com/d-kuro/helmut" "github.com/d-kuro/helmut/assert" "github.com/d-kuro/helmut/util" clientgoscheme "k8s.io/client-go/kubernetes/scheme" ) func TestHelmCharts(t *testing.T) { bytes, err := os.ReadFile(filepath.Join("testdata", "kustomize.yaml")) if err != nil { t.Fatal(err) } const releaseName = "accurate" r := helmut.New() manifests, err := r.RenderTemplates(releaseName, filepath.Join("..", "accurate"), helmut.WithNamespace("accurate"), helmut.WithIncludeCRDs()) if err != nil { t.Fatal(err) } splitManifests, err := util.SplitManifests(bytes) if err != nil { t.Fatal(err) } removeSiffux := func(key helmut.ObjectKey) helmut.ObjectKey { if strings.HasPrefix(key.Name, "accurate-config") { key.Name = "accurate-config" return key } return key } for _, manifest := range splitManifests { obj, _ := util.MustRawManifestToObject(clientgoscheme.Scheme, manifest) key, err := helmut.NewObjectKeyFromObject(obj) if err != nil { t.Fatal(err) } t.Run(key.String(), func(t *testing.T) { assert.Contains(t, manifests, obj, assert.WithAdditionalKeys(removeSiffux)) }) } } ```