diff --git a/README.md b/README.md index a7579c35..dd5b325f 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Depending of the version of the Dynatrace OneAgent Operator, it supports the fol | Dynatrace OneAgent Operator version | Kubernetes | OpenShift Container Platform | | ----------------------------------- | ---------- | ---------------------------- | | master | 1.11+ | 3.11+ | -| v0.4.0 | 1.11+ | 3.11+ | +| v0.4.1 | 1.11+ | 3.11+ | | v0.3.1 | 1.11-1.15 | 3.11+ | | v0.2.1 | 1.9-1.15 | 3.9+ | @@ -44,14 +44,14 @@ Create neccessary objects and observe its logs: #### Kubernetes ```sh $ kubectl create namespace dynatrace -$ kubectl apply -f https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.0/deploy/kubernetes.yaml +$ kubectl apply -f https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.1/deploy/kubernetes.yaml $ kubectl -n dynatrace logs -f deployment/dynatrace-oneagent-operator ``` #### OpenShift ```sh $ oc adm new-project --node-selector="" dynatrace -$ oc apply -f https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.0/deploy/openshift.yaml +$ oc apply -f https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.1/deploy/openshift.yaml $ oc -n dynatrace logs -f deployment/dynatrace-oneagent-operator ``` @@ -110,7 +110,7 @@ spec: # VirtualService and ServiceEntries objects to allow access to the Dynatrace cluster from the agent. #enableIstio: false ``` -Save the snippet to a file or use [./deploy/cr.yaml](https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.0/deploy/cr.yaml) from this repository and adjust its values accordingly. +Save the snippet to a file or use [./deploy/cr.yaml](https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.1/deploy/cr.yaml) from this repository and adjust its values accordingly. A secret holding tokens for authenticating to the Dynatrace cluster needs to be created upfront. Create access tokens of type *Dynatrace API* and *Platform as a Service* and use its values in the following commands respectively. For assistance please refere to [Create user-generated access tokens](https://www.dynatrace.com/support/help/get-started/introduction/why-do-i-need-an-access-token-and-an-environment-id/#create-user-generated-access-tokens). @@ -146,15 +146,18 @@ Remove OneAgent custom resources and clean-up all remaining OneAgent Operator sp #### Kubernetes ```sh $ kubectl delete -n dynatrace oneagent --all -$ kubectl delete -f https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.0/deploy/kubernetes.yaml +$ kubectl delete -f https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.1/deploy/kubernetes.yaml ``` #### OpenShift ```sh $ oc delete -n dynatrace oneagent --all -$ oc delete -f https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.0/deploy/openshift.yaml +$ oc delete -f https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/v0.4.1/deploy/openshift.yaml ``` +## Known Limitation +The `enableIstio` feature requires to restart the operator if Istio was deployed after deployment of the operator in case istio is installed after deploying the operator. +Background: This happens because the cache maintained by controller-runtime's Kubernetes Client is not dynamic. The bug for same is reported here https://github.com/kubernetes-sigs/controller-runtime/issues/321 and the fix for same is currently a work in progress https://github.com/kubernetes-sigs/controller-runtime/pull/554 . ## Hacking diff --git a/deploy/kubernetes.yaml b/deploy/kubernetes.yaml index 67922fd7..7406b0e5 100644 --- a/deploy/kubernetes.yaml +++ b/deploy/kubernetes.yaml @@ -250,7 +250,7 @@ spec: spec: containers: - name: dynatrace-oneagent-operator - image: quay.io/dynatrace/dynatrace-oneagent-operator:v0.4.0 + image: quay.io/dynatrace/dynatrace-oneagent-operator:v0.4.1 command: - dynatrace-oneagent-operator imagePullPolicy: Always diff --git a/deploy/olm/kubernetes/dynatrace-monitoring.v0.4.1.clusterserviceversion.yaml b/deploy/olm/kubernetes/dynatrace-monitoring.v0.4.1.clusterserviceversion.yaml new file mode 100644 index 00000000..9fdc48cc --- /dev/null +++ b/deploy/olm/kubernetes/dynatrace-monitoring.v0.4.1.clusterserviceversion.yaml @@ -0,0 +1,286 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: |- + [{ + "apiVersion": "dynatrace.com/v1alpha1", + "kind": "OneAgent", + "metadata": { + "name": "oneagent", + "namespace": "dynatrace" + }, + "spec": { + "apiUrl": "https://ENVIRONMENTID.live.dynatrace.com/api", + "skipCertCheck": false, + "tokens": "", + "nodeSelector": {}, + "tolerations": [ + { + "effect": "NoSchedule", + "key": "node-role.kubernetes.io/master", + "operator": "Exists" + } + ], + "image": "", + "args": [ + "APP_LOG_CONTENT_ACCESS=1" + ], + "env": [] + } + }] + capabilities: Deep Insights + categories: "Monitoring,Logging & Tracing,OpenShift Optional" + certified: "false" + containerImage: quay.io/dynatrace/dynatrace-oneagent-operator:v0.4.1 + createdAt: 2019-09-17T12:59:59Z + description: Install full-stack monitoring of Kubernetes clusters with the Dynatrace OneAgent. + support: Dynatrace + repository: https://github.com/Dynatrace/dynatrace-oneagent-operator + name: dynatrace-monitoring.v0.4.1 + namespace: "placeholder" +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: Dyantrace OneAgent for full-stack monitoring + displayName: Dynatrace OneAgent + kind: OneAgent + name: oneagents.dynatrace.com + resources: + - kind: DaemonSet + name: "" + version: v1beta2 + - kind: Pod + name: "" + version: v1 + specDescriptors: + - description: Credentials for the OneAgent to connect back to Dynatrace. + displayName: API and PaaS Tokens + path: tokens + x-descriptors: + - 'urn:alm:descriptor:io.kubernetes:core:v1:Secret' + - description: 'Location of the Dynatrace API to connect to, including your specific environment ID' + displayName: API URL + path: apiUrl + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Specifies if certificate checks should be skipped. + displayName: Skip Certificate Check + path: skipCertCheck + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:booleanCheck' + - description: Node selector for where pods should be scheduled. + displayName: Node Selector + path: nodeSelector + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Node' + - description: The Dynatrace installer container image. + displayName: Image + path: image + - description: Define resources requests and limits for single Pods + displayName: Resource Requirements + path: resources + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:resourceRequirements' + statusDescriptors: + - description: Dynatrace version being used. + displayName: Version + path: version + - description: The timestamp when the instance was last updated. + displayName: Last Updated + path: updatedTimestamp + x-descriptors: + - 'urn:alm:descriptor:timestamp' + version: v1alpha1 + description: | + The Dynatrace OneAgent Operator allows users to easily deploy full-stack monitoring for [Kubernetes clusters](https://www.dynatrace.com/technologies/kubernetes-monitoring/). The Dynatrace OneAgent automatically monitors the workload running in containers down to the code and request level. + + ### Before You Start + Add a Secret within the Namespace you're deploying the Dynatrace Operator to, which would contain your API and PaaS tokens. Create tokens of type *Dynatrace API* (`API_TOKEN`) and *Platform as a Service* (`PAAS_TOKEN`) and use their values in the following commands respectively. For assistance please refer to [Create user-generated access tokens](https://www.dynatrace.com/support/help/shortlink/token#create-user-generated-access-tokens). + + ``` $ kubectl -n dynatrace create secret generic oneagent --from-literal="apiToken=API_TOKEN" --from-literal="paasToken=PAAS_TOKEN" ``` + + You may update this Secret at any time to rotate the tokens. + + ### Required Parameters + * `apiUrl` - provide the URL to the API of your Dynatrace environment. In Dynatrace SaaS it will look like `https://.live.dynatrace.com/api` . In Dynatrace Managed like `https:///e//api` . + + ### Advanced Options + * **Image Override** - use a copy of the OneAgent container image from a registry other than Docker's or Red Hat's + * **NodeSelectors** - select a subset of your cluster's nodes to run the Dynatrace OneAgent on, based on labels + * **Tolerations** - add specific tolerations to the agent so that it can monitor all of the nodes in your cluster; we include the default toleration so that Dynatrace OneAgent also monitors the master nodes + * **Priority Class Name** - define the priorityClassName for OneAgent pods + * **Environment variables** - define environment variables for the OneAgent container + * **Disable Certificate Checking** - disable any certificate validation that may interact poorly with proxies with in your cluster + * **Disable OneAgent Update** - disable the Operator's auto-update feature for OneAgent pods + * **Enable Istio Auto-config** - automatically create Istio objects for egress communication to the Dynatrace environment from the OneAgent + + For a complete list of supported parameters please consult the [Operator Deploy Guide](https://www.dynatrace.com/support/help/shortlink/kubernetes-deploy). + displayName: Dynatrace OneAgent + icon: + - base64data: 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 + mediatype: "image/png" + install: + spec: + deployments: + - name: dynatrace-operator + spec: + replicas: 1 + selector: + matchLabels: + name: dynatrace-oneagent-operator + template: + metadata: + labels: + dynatrace: operator + name: dynatrace-oneagent-operator + operator: oneagent + spec: + containers: + - command: + - dynatrace-oneagent-operator + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + image: quay.io/dynatrace/dynatrace-oneagent-operator:v0.4.1 + imagePullPolicy: Always + name: dynatrace-oneagent-operator + resources: + limits: + cpu: 200m + memory: 128Mi + requests: + cpu: 100m + memory: 64Mi + nodeSelector: + beta.kubernetes.io/os: linux + serviceAccountName: dynatrace-oneagent-operator + permissions: + - serviceAccountName: dynatrace-oneagent-operator + rules: + - apiGroups: + - dynatrace.com + resources: + - oneagents + verbs: + - get + - list + - watch + - update + - apiGroups: + - apps + resources: + - daemonsets + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch + - delete + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create + - apiGroups: + - dynatrace.com + resources: + - oneagents/finalizers + - oneagents/status + verbs: + - update + - apiGroups: + - networking.istio.io + resources: + - serviceentries + - virtualservices + verbs: + - get + - list + - create + - update + - delete + - apiGroups: + - policy + resources: + - podsecuritypolicies + resourceNames: + - dynatrace-oneagent-operator + verbs: + - use + - serviceAccountName: dynatrace-oneagent + rules: + - apiGroups: + - policy + resources: + - podsecuritypolicies + resourceNames: + - dynatrace-oneagent + verbs: + - use + strategy: deployment + installModes: + - type: OwnNamespace + supported: true + - type: SingleNamespace + supported: true + - type: MultiNamespace + supported: false + - type: AllNamespaces + supported: false + keywords: + - monitoring + - dynatrace + - oneagent + links: + - name: Operator Deploy Guide + url: https://www.dynatrace.com/support/help/shortlink/kubernetes-deploy + - name: Kubernetes Monitoring Info + url: https://www.dynatrace.com/technologies/kubernetes-monitoring + maintainers: + - email: support@dynatrace.com + name: Dynatrace LLC + maturity: alpha + provider: + name: Dynatrace LLC + replaces: dynatrace-monitoring.v0.3.1 + version: 0.4.1 + minKubeVersion: 1.11.0 diff --git a/deploy/olm/kubernetes/dynatrace.package.yaml b/deploy/olm/kubernetes/dynatrace.package.yaml index 0ff6e8de..846d3071 100644 --- a/deploy/olm/kubernetes/dynatrace.package.yaml +++ b/deploy/olm/kubernetes/dynatrace.package.yaml @@ -1,4 +1,4 @@ packageName: oneagent channels: - name: alpha - currentCSV: dynatrace-monitoring.v0.3.1 + currentCSV: dynatrace-monitoring.v0.4.1 diff --git a/deploy/olm/openshift/dynatrace-monitoring.v0.4.1.clusterserviceversion.yaml b/deploy/olm/openshift/dynatrace-monitoring.v0.4.1.clusterserviceversion.yaml new file mode 100644 index 00000000..0c51928a --- /dev/null +++ b/deploy/olm/openshift/dynatrace-monitoring.v0.4.1.clusterserviceversion.yaml @@ -0,0 +1,279 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: |- + [{ + "apiVersion": "dynatrace.com/v1alpha1", + "kind": "OneAgent", + "metadata": { + "name": "oneagent", + "namespace": "dynatrace" + }, + "spec": { + "apiUrl": "https://ENVIRONMENTID.live.dynatrace.com/api", + "skipCertCheck": false, + "tokens": "", + "nodeSelector": {}, + "tolerations": [ + { + "effect": "NoSchedule", + "key": "node-role.kubernetes.io/master", + "operator": "Exists" + } + ], + "image": "registry.connect.redhat.com/dynatrace/oneagent", + "args": [ + "APP_LOG_CONTENT_ACCESS=1" + ], + "env": [] + } + }] + capabilities: Deep Insights + categories: "Monitoring,Logging & Tracing,OpenShift Optional" + certified: "false" + containerImage: registry.connect.redhat.com/dynatrace/dynatrace-oneagent-operator:v0.4.1 + createdAt: 2019-09-17T12:59:59Z + description: Install full-stack monitoring of OpenShift clusters with the Dynatrace OneAgent. + support: Dynatrace + repository: https://github.com/Dynatrace/dynatrace-oneagent-operator + name: dynatrace-monitoring.v0.4.1 + namespace: "placeholder" +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: Dyantrace OneAgent for full-stack monitoring + displayName: Dynatrace OneAgent + kind: OneAgent + name: oneagents.dynatrace.com + resources: + - kind: DaemonSet + name: "" + version: v1beta2 + - kind: Pod + name: "" + version: v1 + specDescriptors: + - description: Credentials for the OneAgent to connect back to Dynatrace. + displayName: API and PaaS Tokens + path: tokens + x-descriptors: + - 'urn:alm:descriptor:io.kubernetes:core:v1:Secret' + - description: 'Location of the Dynatrace API to connect to, including your specific environment ID' + displayName: API URL + path: apiUrl + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Specifies if certificate checks should be skipped. + displayName: Skip Certificate Check + path: skipCertCheck + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:booleanCheck' + - description: Node selector for where pods should be scheduled. + displayName: Node Selector + path: nodeSelector + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Node' + - description: The Dynatrace installer container image. + displayName: Image + path: image + - description: Define resources requests and limits for single Pods + displayName: Resource Requirements + path: resources + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:resourceRequirements' + statusDescriptors: + - description: Dynatrace version being used. + displayName: Version + path: version + - description: The timestamp when the instance was last updated. + displayName: Last Updated + path: updatedTimestamp + x-descriptors: + - 'urn:alm:descriptor:timestamp' + version: v1alpha1 + description: | + The Dynatrace OneAgent Operator allows users to easily deploy full-stack monitoring for [OpenShift clusters](https://www.dynatrace.com/technologies/openshift-monitoring/). The Dynatrace OneAgent automatically monitors the workload running in containers down to the code and request level. + + ### Before You Start + Add a Secret within the Project you're deploying the Dynatrace Operator to, which would contain your API and PaaS tokens. Create tokens of type *Dynatrace API* (`API_TOKEN`) and *Platform as a Service* (`PAAS_TOKEN`) and use their values in the following commands respectively. For assistance please refer to [Create user-generated access tokens](https://www.dynatrace.com/support/help/shortlink/token#create-user-generated-access-tokens). + + ``` $ oc -n dynatrace create secret generic oneagent --from-literal="apiToken=API_TOKEN" --from-literal="paasToken=PAAS_TOKEN" ``` + + You may update this Secret at any time to rotate the tokens. + ### Required Parameters + * `apiUrl` - provide the URL to the API of your Dynatrace environment. In Dynatrace SaaS it will look like `https://.live.dynatrace.com/api` . In Dynatrace Managed like `https:///e//api` . + + ### Advanced Options + * **Image Override** - use a copy of the OneAgent container image from a registry other than Docker's or Red Hat's + * **NodeSelectors** - select a subset of your cluster's nodes to run the Dynatrace OneAgent on, based on labels + * **Tolerations** - add specific tolerations to the agent so that it can monitor all of the nodes in your cluster; we include the default toleration so that Dynatrace OneAgent also monitors the master nodes + * **Priority Class Name** - define the priorityClassName for OneAgent pods + * **Environment variables** - define environment variables for the OneAgent container + * **Disable Certificate Checking** - disable any certificate validation that may interact poorly with proxies with in your cluster + * **Disable OneAgent Update** - disable the Operator's auto-update feature for OneAgent pods + * **Enable Istio Auto-config** - automatically create Istio objects for egress communication to the Dynatrace environment from the OneAgent + + For a complete list of supported parameters please consult the [Operator Deploy Guide](https://www.dynatrace.com/support/help/shortlink/openshift-deploy). + displayName: Dynatrace OneAgent + icon: + - base64data: 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 + mediatype: "image/png" + install: + spec: + deployments: + - name: dynatrace-operator + spec: + replicas: 1 + selector: + matchLabels: + name: dynatrace-oneagent-operator + template: + metadata: + labels: + dynatrace: operator + name: dynatrace-oneagent-operator + operator: oneagent + spec: + containers: + - command: + - dynatrace-oneagent-operator + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + image: registry.connect.redhat.com/dynatrace/dynatrace-oneagent-operator:v0.4.1 + imagePullPolicy: Always + name: dynatrace-oneagent-operator + resources: + limits: + cpu: 200m + memory: 128Mi + requests: + cpu: 100m + memory: 64Mi + nodeSelector: + beta.kubernetes.io/os: linux + serviceAccountName: dynatrace-oneagent-operator + permissions: + - serviceAccountName: dynatrace-oneagent-operator + rules: + - apiGroups: + - dynatrace.com + resources: + - oneagents + verbs: + - get + - list + - watch + - update + - apiGroups: + - apps + resources: + - daemonsets + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - delete + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch + - delete + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create + - apiGroups: + - dynatrace.com + resources: + - oneagents/finalizers + - oneagents/status + verbs: + - update + - apiGroups: + - networking.istio.io + resources: + - serviceentries + - virtualservices + verbs: + - get + - list + - create + - update + - delete + clusterPermissions: + - serviceAccountName: dynatrace-oneagent + rules: + - verbs: + - use + apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + resourceNames: + - privileged + - host + strategy: deployment + installModes: + - type: OwnNamespace + supported: true + - type: SingleNamespace + supported: true + - type: MultiNamespace + supported: false + - type: AllNamespaces + supported: false + keywords: + - monitoring + - dynatrace + - oneagent + links: + - name: Operator Deploy Guide + url: https://www.dynatrace.com/support/help/shortlink/openshift-deploy + - name: OpenShift Monitoring Info + url: https://www.dynatrace.com/technologies/openshift-monitoring + maintainers: + - email: support@dynatrace.com + name: Dynatrace LLC + maturity: alpha + provider: + name: Dynatrace LLC + replaces: dynatrace-monitoring.v0.3.1 + version: 0.4.1 + minKubeVersion: 1.11.0 diff --git a/deploy/olm/openshift/dynatrace.package.yaml b/deploy/olm/openshift/dynatrace.package.yaml index 0ff6e8de..c998867c 100644 --- a/deploy/olm/openshift/dynatrace.package.yaml +++ b/deploy/olm/openshift/dynatrace.package.yaml @@ -1,4 +1,4 @@ -packageName: oneagent +packageName: oneagent-certified channels: - name: alpha - currentCSV: dynatrace-monitoring.v0.3.1 + currentCSV: dynatrace-monitoring.v0.4.1 diff --git a/deploy/openshift.yaml b/deploy/openshift.yaml index c031c9e6..8e32a835 100644 --- a/deploy/openshift.yaml +++ b/deploy/openshift.yaml @@ -184,7 +184,7 @@ spec: spec: containers: - name: dynatrace-oneagent-operator - image: registry.connect.redhat.com/dynatrace/dynatrace-oneagent-operator:v0.4.0 + image: registry.connect.redhat.com/dynatrace/dynatrace-oneagent-operator:v0.4.1 command: - dynatrace-oneagent-operator imagePullPolicy: Always diff --git a/pkg/controller/istio/helper.go b/pkg/controller/istio/helper.go index 59a9e0e5..9024be51 100644 --- a/pkg/controller/istio/helper.go +++ b/pkg/controller/istio/helper.go @@ -3,11 +3,16 @@ package istio import ( "crypto/sha256" "encoding/hex" + "fmt" + "net" "os" "strconv" "strings" + istiov1alpha3 "github.com/Dynatrace/dynatrace-oneagent-operator/pkg/apis/networking/istio/v1alpha3" "github.com/operator-framework/operator-sdk/pkg/k8sutil" + istio "istio.io/api/networking/v1alpha3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/discovery" "k8s.io/client-go/rest" @@ -51,107 +56,125 @@ func CheckIstioEnabled(cfg *rest.Config) (bool, error) { } // BuildServiceEntry returns an Istio ServiceEntry object for the given communication endpoint. -func BuildServiceEntry(name string, host string, port uint32, protocol string) []byte { - portStr := strconv.Itoa(int(port)) - protocolStr := strings.ToUpper(protocol) +func BuildServiceEntry(name, host, protocol string, port uint32) *istiov1alpha3.ServiceEntry { + if net.ParseIP(host) != nil { // It's an IP. + return buildServiceEntryIP(name, host, port) + } - return []byte(`{ - "apiVersion": "networking.istio.io/v1alpha3", - "kind": "ServiceEntry", - "metadata": { - "name": "` + name + `", - "namespace": "` + os.Getenv(k8sutil.WatchNamespaceEnvVar) + `" - }, - "spec": { - "hosts": [ "` + host + `" ], - "location": "MESH_EXTERNAL", - "ports": [{ - "name": "` + protocol + portStr + `", - "number": ` + portStr + `, - "protocol": "` + protocolStr + `" - }], - "resolution": "DNS" - } -}`) + return buildServiceEntryFQDN(name, host, protocol, port) } // BuildVirtualService returns an Istio VirtualService object for the given communication endpoint. -func BuildVirtualService(name string, host string, port uint32, protocol string) []byte { - switch protocol { - case "https": - return buildVirtualServiceHTTPS(name, host, port) - case "http": - return buildVirtualServiceHTTP(name, host, port) +func BuildVirtualService(name, host, protocol string, port uint32) *istiov1alpha3.VirtualService { + if net.ParseIP(host) != nil { // It's an IP. + return nil } - return []byte(`{}`) + return &istiov1alpha3.VirtualService{ + ObjectMeta: buildObjectMeta(name), + Spec: buildVirtualServiceSpec(host, protocol, port), + } } -func buildVirtualServiceHTTPS(name string, host string, port uint32) []byte { +// buildServiceEntryFQDN returns an Istio ServiceEntry object for the given communication endpoint with a FQDN host. +func buildServiceEntryFQDN(name, host, protocol string, port uint32) *istiov1alpha3.ServiceEntry { portStr := strconv.Itoa(int(port)) + protocolStr := strings.ToUpper(protocol) - return []byte(`{ - "apiVersion": "networking.istio.io/v1alpha3", - "kind": "VirtualService", - "metadata": { - "name": "` + name + `", - "namespace": "` + os.Getenv(k8sutil.WatchNamespaceEnvVar) + `" - }, - "spec": { - "hosts": [ "` + host + `" ], - "tls": [{ - "match": [{ - "port": ` + portStr + `, - "sni_hosts": [ "` + host + `" ] - }], - "route": [{ - "destination": { - "host": "` + host + `", - "port": { "number": ` + portStr + ` } - } - }] - }] - } -}`) + return &istiov1alpha3.ServiceEntry{ + ObjectMeta: buildObjectMeta(name), + Spec: istiov1alpha3.ServiceEntrySpec{ + ServiceEntry: istio.ServiceEntry{ + Hosts: []string{host}, + Ports: []*istio.Port{{ + Name: protocol + "-" + portStr, + Number: port, + Protocol: protocolStr, + }}, + Location: istio.ServiceEntry_MESH_EXTERNAL, + Resolution: istio.ServiceEntry_DNS, + }, + }, + } } -func buildVirtualServiceHTTP(name string, host string, port uint32) []byte { +// buildServiceEntryIP returns an Istio ServiceEntry object for the given communication endpoint with IP. +func buildServiceEntryIP(name, host string, port uint32) *istiov1alpha3.ServiceEntry { portStr := strconv.Itoa(int(port)) - return []byte(`{ - "apiVersion": "networking.istio.io/v1alpha3", - "kind": "VirtualService", - "metadata": { - "name": "` + name + `", - "namespace": "` + os.Getenv(k8sutil.WatchNamespaceEnvVar) + `" - }, - "spec": { - "hosts": [ "` + host + `" ], - "http": [{ - "match": [{ - "port": ` + portStr + `, - "headers": [{ "Host": "` + host + `" }] - }], - "route": [{ - "destination": { - "host": "` + host + `", - "port": { "number": ` + portStr + ` } - } - }] - }] - } -}`) + return &istiov1alpha3.ServiceEntry{ + ObjectMeta: buildObjectMeta(name), + Spec: istiov1alpha3.ServiceEntrySpec{ + ServiceEntry: istio.ServiceEntry{ + Hosts: []string{"ignored.subdomain"}, + Addresses: []string{host + "/32"}, + Ports: []*istio.Port{{ + Name: "TCP-" + portStr, + Number: port, + Protocol: "TCP", + }}, + Location: istio.ServiceEntry_MESH_EXTERNAL, + Resolution: istio.ServiceEntry_NONE, + }, + }, + } } // BuildNameForEndpoint returns a name to be used as a base to identify Istio objects. -func BuildNameForEndpoint(name string, host string, port uint32) string { - portStr := strconv.Itoa(int(port)) - src := make([]byte, len(name)+len(host)+len(portStr)) - src = strconv.AppendQuote(src, name) - src = strconv.AppendQuote(src, host) - src = strconv.AppendQuote(src, portStr) +func BuildNameForEndpoint(name string, protocol string, host string, port uint32) string { + sum := sha256.Sum256([]byte(fmt.Sprintf("%s-%s-%s-%d", name, protocol, host, port))) + return hex.EncodeToString(sum[:]) +} - sum := sha256.Sum256(src) +func buildVirtualServiceSpec(host, protocol string, port uint32) istiov1alpha3.VirtualServiceSpec { + virtualServiceSpec := istiov1alpha3.VirtualServiceSpec{} + virtualServiceSpec.Hosts = []string{host} + switch protocol { + case "https": + virtualServiceSpec.Tls = buildVirtualServiceTLSRoute(host, port) + case "http": + virtualServiceSpec.Http = buildVirtualServiceHttpRoute(port, host) + } - return hex.EncodeToString(sum[:]) + return virtualServiceSpec +} + +func buildVirtualServiceTLSRoute(host string, port uint32) []*istio.TLSRoute { + return []*istio.TLSRoute{{ + Match: []*istio.TLSMatchAttributes{{ + SniHosts: []string{host}, + Port: port, + }}, + Route: []*istio.RouteDestination{{ + Destination: &istio.Destination{ + Host: host, + Port: &istio.PortSelector{ + Port: &istio.PortSelector_Number{Number: port}, + }, + }, + }}, + }} +} + +func buildVirtualServiceHttpRoute(port uint32, host string) []*istio.HTTPRoute { + return []*istio.HTTPRoute{{ + Match: []*istio.HTTPMatchRequest{{ + Port: port, + }}, + Route: []*istio.HTTPRouteDestination{{ + Destination: &istio.Destination{ + Host: host, + Port: &istio.PortSelector{ + Port: &istio.PortSelector_Number{Number: port}, + }, + }, + }}, + }} +} + +func buildObjectMeta(name string) v1.ObjectMeta { + return v1.ObjectMeta{ + Name: name, + Namespace: os.Getenv(k8sutil.WatchNamespaceEnvVar), + } } diff --git a/pkg/controller/istio/helper_test.go b/pkg/controller/istio/helper_test.go index d4dce2a9..f853caec 100644 --- a/pkg/controller/istio/helper_test.go +++ b/pkg/controller/istio/helper_test.go @@ -1,14 +1,18 @@ package istio import ( + "bytes" "encoding/json" "net/http" "net/http/httptest" + "os" "testing" - restclient "k8s.io/client-go/rest" - + istiov1alpha3 "github.com/Dynatrace/dynatrace-oneagent-operator/pkg/apis/networking/istio/v1alpha3" + "github.com/operator-framework/operator-sdk/pkg/k8sutil" + "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + restclient "k8s.io/client-go/rest" ) func initMockServer(t *testing.T, list *metav1.APIGroupList) *httptest.Server { @@ -95,3 +99,127 @@ func TestIstioWrongConfig(t *testing.T) { t.Error("got true, expected false with error") } } + +func TestServiceEntryGeneration(t *testing.T) { + // TODO: don't use environment variable on BuildServiceEntry + os.Setenv(k8sutil.WatchNamespaceEnvVar, "dynatrace") + + seTest1 := bytes.NewBufferString(`{ + "apiVersion": "networking.istio.io/v1alpha3", + "kind": "ServiceEntry", + "metadata": { + "name": "com1", + "namespace": "dynatrace" + }, + "spec": { + "hosts": [ "comtest.com" ], + "location": "MESH_EXTERNAL", + "ports": [{ + "name": "https-9999", + "number": 9999, + "protocol": "HTTPS" + }], + "resolution": "DNS" + } + }`) + + se := istiov1alpha3.ServiceEntry{} + err := json.Unmarshal(seTest1.Bytes(), &se) + if err != nil { + t.Error(err) + } + assert.ObjectsAreEqualValues(&se, (BuildServiceEntry("com1", "comtest.com", "https", 9999))) + + seTest2 := bytes.NewBufferString(`{ + "apiVersion": "networking.istio.io/v1alpha3", + "kind": "ServiceEntry", + "metadata": { + "name": "com1", + "namespace": "dynatrace" + }, + "spec": { + "hosts": [ "ignored.subdomain" ], + "addresses": [ "42.42.42.42/32" ], + "location": "MESH_EXTERNAL", + "ports": [{ + "name": "TCP-8888", + "number": 8888, + "protocol": "TCP" + }], + "resolution": "NONE" + } + }`) + se = istiov1alpha3.ServiceEntry{} + err = json.Unmarshal(seTest2.Bytes(), &se) + if err != nil { + t.Error(err) + } + assert.ObjectsAreEqualValues(&se, (BuildServiceEntry("com1", "42.42.42.42", "https", 8888))) +} + +func TestVirtualServiceGeneration(t *testing.T) { + // TODO: don't use environment variable on BuildServiceEntry + os.Setenv(k8sutil.WatchNamespaceEnvVar, "dynatrace") + vsTest1 := bytes.NewBufferString(`{ + "apiVersion": "networking.istio.io/v1alpha3", + "kind": "VirtualService", + "metadata": { + "name": "com1", + "namespace": "dynatrace" + }, + "spec": { + "hosts": [ "comtest.com" ], + "tls": [{ + "match": [{ + "port": 8888, + "sni_hosts": [ "comtest.com" ] + }], + "route": [{ + "destination": { + "host": "comtest.com", + "port": { "number": 8888 } + } + }] + }] + } + }`) + + vs := istiov1alpha3.VirtualService{} + err := json.Unmarshal(vsTest1.Bytes(), &vs) + if err != nil { + t.Error(err) + } + assert.ObjectsAreEqualValues(&vs, BuildVirtualService("com1", "comtest.com", "https", 8888)) + + vsTest2 := bytes.NewBufferString(`{ + "apiVersion": "networking.istio.io/v1alpha3", + "kind": "VirtualService", + "metadata": { + "name": "com1", + "namespace": "dynatrace" + }, + "spec": { + "hosts": [ "comtest.com" ], + "http": [{ + "match": [{ + "port": 7777 + }], + "route": [{ + "destination": { + "host": "comtest.com", + "port": { "number": 7777 } + } + }] + }] + } + }`) + + vs = istiov1alpha3.VirtualService{} + err = json.Unmarshal(vsTest2.Bytes(), &vs) + if err != nil { + t.Error(err) + } + assert.ObjectsAreEqualValues(&vs, BuildVirtualService("com1", "comtest.com", "http", 7777)) + + assert.Nil(t, BuildVirtualService("com1", "42.42.42.42", "HTTP", 8888)) +} diff --git a/pkg/controller/oneagent/istio.go b/pkg/controller/oneagent/istio.go index 82c0d089..db72cfa3 100644 --- a/pkg/controller/oneagent/istio.go +++ b/pkg/controller/oneagent/istio.go @@ -2,23 +2,24 @@ package oneagent import ( "context" - "encoding/json" "fmt" "os" dynatracev1alpha1 "github.com/Dynatrace/dynatrace-oneagent-operator/pkg/apis/dynatrace/v1alpha1" versionedistioclient "github.com/Dynatrace/dynatrace-oneagent-operator/pkg/apis/networking/clientset/versioned" + istiov1alpha3 "github.com/Dynatrace/dynatrace-oneagent-operator/pkg/apis/networking/istio/v1alpha3" "github.com/Dynatrace/dynatrace-oneagent-operator/pkg/controller/istio" + istiohelper "github.com/Dynatrace/dynatrace-oneagent-operator/pkg/controller/istio" dtclient "github.com/Dynatrace/dynatrace-oneagent-operator/pkg/dynatrace-client" "github.com/go-logr/logr" "github.com/operator-framework/operator-sdk/pkg/k8sutil" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) func (r *ReconcileOneAgent) reconcileIstio(logger logr.Logger, instance *dynatracev1alpha1.OneAgent, dtc dtclient.Client) (updated bool, ok bool) { @@ -80,7 +81,7 @@ func (r *ReconcileOneAgent) reconcileIstioConfigurations( role string, logger logr.Logger) (bool, error) { - add := r.reconcileIstioCreateConfigurations(instance, comHosts, role, logger) + add := r.reconcileIstioCreateConfigurations(instance, ic, comHosts, role, logger) rem := r.reconcileIstioRemoveConfigurations(instance, ic, comHosts, role, logger) return add || rem, nil } @@ -99,7 +100,7 @@ func (r *ReconcileOneAgent) reconcileIstioRemoveConfigurations( seen := map[string]bool{} for _, ch := range comHosts { - seen[istio.BuildNameForEndpoint(instance.Name, ch.Host, ch.Port)] = true + seen[istiohelper.BuildNameForEndpoint(instance.Name, ch.Protocol, ch.Host, ch.Port)] = true } vsUpd := r.removeIstioConfigurationForVirtualService(ic, listOps, seen, logger) @@ -122,7 +123,6 @@ func (r *ReconcileOneAgent) removeIstioConfigurationForServiceEntry( seen map[string]bool, logger logr.Logger) bool { - gvk := istio.ServiceEntryGVK namespace := os.Getenv(k8sutil.WatchNamespaceEnvVar) list, err := ic.NetworkingV1alpha3().ServiceEntries(namespace).List(*listOps) @@ -134,7 +134,7 @@ func (r *ReconcileOneAgent) removeIstioConfigurationForServiceEntry( del := false for _, se := range list.Items { if _, inUse := seen[se.GetName()]; !inUse { - logger.Info(fmt.Sprintf("istio: removing %s: %v", gvk.Kind, se.GetName())) + logger.Info(fmt.Sprintf("istio: removing %s: %v", se.Kind, se.GetName())) err = ic.NetworkingV1alpha3(). ServiceEntries(namespace). Delete(se.GetName(), &metav1.DeleteOptions{}) @@ -155,7 +155,6 @@ func (r *ReconcileOneAgent) removeIstioConfigurationForVirtualService( seen map[string]bool, logger logr.Logger) bool { - gvk := istio.VirtualServiceGVK namespace := os.Getenv(k8sutil.WatchNamespaceEnvVar) list, err := ic.NetworkingV1alpha3().VirtualServices(namespace).List(*listOps) @@ -167,7 +166,7 @@ func (r *ReconcileOneAgent) removeIstioConfigurationForVirtualService( del := false for _, vs := range list.Items { if _, inUse := seen[vs.GetName()]; !inUse { - logger.Info(fmt.Sprintf("istio: removing %s: %v", gvk.Kind, vs.GetName())) + logger.Info(fmt.Sprintf("istio: removing %s: %v", vs.Kind, vs.GetName())) err = ic.NetworkingV1alpha3(). VirtualServices(namespace). Delete(vs.GetName(), &metav1.DeleteOptions{}) @@ -181,28 +180,58 @@ func (r *ReconcileOneAgent) removeIstioConfigurationForVirtualService( return del } -func (r *ReconcileOneAgent) reconcileIstioCreateConfigurations(instance *dynatracev1alpha1.OneAgent, - comHosts []dtclient.CommunicationHost, role string, logger logr.Logger) bool { +func (r *ReconcileOneAgent) reconcileIstioCreateConfigurations( + instance *dynatracev1alpha1.OneAgent, + ic *versionedistioclient.Clientset, + comHosts []dtclient.CommunicationHost, + role string, logger logr.Logger) bool { created := false - for _, ch := range comHosts { - name := istio.BuildNameForEndpoint(instance.Name, ch.Host, ch.Port) + if _, err := r.configurationNotFound(istio.ServiceEntryGVK, instance.Namespace, ""); meta.IsNoMatchError(err) { + logger.Info("istio: failed to query ServiceEntry: CRD is not registered. Did you install Istio recently? Please restart the Operator") + return created + } + + if _, err := r.configurationNotFound(istio.VirtualServiceGVK, instance.Namespace, ""); meta.IsNoMatchError(err) { + logger.Info("istio: failed to query VirtualService: CRD is not registered. Did you install Istio recently? Please restart the Operator") + return created + } - if notFound := r.configurationExists(istio.ServiceEntryGVK, instance.Namespace, name); notFound { + for _, ch := range comHosts { + name := istiohelper.BuildNameForEndpoint(instance.Name, ch.Protocol, ch.Host, ch.Port) + + // Regarding the IsNoMatchError() checks, it's a workaround for, + // https://github.com/kubernetes-sigs/controller-runtime/issues/321 + // + // The controller-runtime Client caches CRDs when the process start and doesn't refresh them, so if Istio is + // installed into Kubernetes after the Operator instance was started, we'll get errors when querying for + // ServiceEntries, etc. + // + // While there is a pending fix for the bug, since this is a minor edge case, we can suggest to the customer to + // restart the Operator pod. + if notFound, err := r.configurationNotFound(istio.ServiceEntryGVK, instance.Namespace, name); err != nil { + logger.Error(err, "istio: failed to query ServiceEntry") + continue + } else if notFound { logger.Info("istio: creating ServiceEntry", "objectName", name, "host", ch.Host, "port", ch.Port) - payload := istio.BuildServiceEntry(name, ch.Host, ch.Port, ch.Protocol) - if err := r.reconcileIstioCreateConfiguration(instance, istio.ServiceEntryGVK, role, payload); err != nil { + serviceEntry := istiohelper.BuildServiceEntry(name, ch.Host, ch.Protocol, ch.Port) + + if err := r.createIstioConfigurationForServiceEntry(instance, ic, serviceEntry, role, logger); err != nil { logger.Error(err, "istio: failed to create ServiceEntry") continue } created = true } - if notFound := r.configurationExists(istio.VirtualServiceGVK, instance.Namespace, name); notFound { + if notFound, err := r.configurationNotFound(istio.VirtualServiceGVK, instance.Namespace, name); err != nil { + logger.Error(err, "istio: failed to query VirtualService") + continue + } else if notFound { logger.Info("istio: creating VirtualService", "objectName", name, "host", ch.Host, "port", ch.Port, "protocol", ch.Protocol) - payload := istio.BuildVirtualService(name, ch.Host, ch.Port, ch.Protocol) - if err := r.reconcileIstioCreateConfiguration(instance, istio.VirtualServiceGVK, role, payload); err != nil { + virtualService := istio.BuildVirtualService(name, ch.Host, ch.Protocol, ch.Port) + + if err := r.createIstioConfigurationForVirtualService(instance, ic, virtualService, role, logger); err != nil { logger.Error(err, "istio: failed to create VirtualService") } created = true @@ -212,38 +241,71 @@ func (r *ReconcileOneAgent) reconcileIstioCreateConfigurations(instance *dynatra return created } -func (r *ReconcileOneAgent) reconcileIstioCreateConfiguration(instance *dynatracev1alpha1.OneAgent, - gvk schema.GroupVersionKind, role string, payload []byte) error { +func (r *ReconcileOneAgent) createIstioConfigurationForServiceEntry( + oneagent *dynatracev1alpha1.OneAgent, + ic *versionedistioclient.Clientset, + serviceEntry *istiov1alpha3.ServiceEntry, + role string, logger logr.Logger) error { - var obj unstructured.Unstructured - obj.Object = make(map[string]interface{}) + namespace := os.Getenv(k8sutil.WatchNamespaceEnvVar) + serviceEntry.Labels = buildIstioLabels(oneagent.Name, role) - if err := json.Unmarshal(payload, &obj.Object); err != nil { - return fmt.Errorf("failed to unmarshal json (%s): %v", payload, err) + sve, err := ic.NetworkingV1alpha3().ServiceEntries(namespace).Create(serviceEntry) + if err != nil { + err = fmt.Errorf("istio: error listing service entries, %v", err) + logger.Error(err, "istio reconcile") + return err } + if sve == nil { + err := fmt.Errorf("Could not create service entry with spec %v", serviceEntry.Spec) + logger.Error(err, "istio reconcile") + return err + } + return nil +} - obj.SetGroupVersionKind(gvk) - obj.SetLabels(buildIstioLabels(instance.Name, role)) +func (r *ReconcileOneAgent) createIstioConfigurationForVirtualService( + oneagent *dynatracev1alpha1.OneAgent, + ic *versionedistioclient.Clientset, + virtualService *istiov1alpha3.VirtualService, + role string, logger logr.Logger) error { - if err := controllerutil.SetControllerReference(instance, &obj, r.scheme); err != nil { - return fmt.Errorf("failed to set owner reference: %v", err) - } + namespace := os.Getenv(k8sutil.WatchNamespaceEnvVar) + virtualService.Labels = buildIstioLabels(oneagent.Name, role) - if err := r.client.Create(context.TODO(), &obj); err != nil { - return fmt.Errorf("failed to create Istio configuration: %v", err) + vs, err := ic.NetworkingV1alpha3().VirtualServices(namespace).Create(virtualService) + if err != nil { + err = fmt.Errorf("istio: error listing service entries, %v", err) + logger.Error(err, "istio reconcile") + return err + } + if vs == nil { + err := fmt.Errorf("Could not create service entry with spec %v", virtualService.Spec) + logger.Error(err, "istio reconcile") + return err } - return nil } -func (r *ReconcileOneAgent) configurationExists(gvk schema.GroupVersionKind, namespace string, name string) bool { +func (r *ReconcileOneAgent) configurationNotFound(gvk schema.GroupVersionKind, namespace string, name string) (bool, error) { var objQuery unstructured.Unstructured objQuery.Object = make(map[string]interface{}) objQuery.SetGroupVersionKind(gvk) - key := client.ObjectKey{Namespace: namespace, Name: name} - return errors.IsNotFound(r.client.Get(context.TODO(), key, &objQuery)) + var err error + if name == "" { + err = r.client.List(context.TODO(), &client.ListOptions{Namespace: namespace}, &objQuery) + } else { + err = r.client.Get(context.TODO(), client.ObjectKey{Namespace: namespace, Name: name}, &objQuery) + } + + if err == nil { // Object found. + return false, nil + } else if errors.IsNotFound(err) { // Object not found. + return true, nil + } + return false, err // Other errors } func buildIstioLabels(name, role string) map[string]string { diff --git a/pkg/controller/oneagent/istio_test.go b/pkg/controller/oneagent/istio_test.go index 694cfb1e..467e1942 100644 --- a/pkg/controller/oneagent/istio_test.go +++ b/pkg/controller/oneagent/istio_test.go @@ -36,13 +36,8 @@ func TestIstioClient_CreateIstioObjects(t *testing.T) { func TestIstioClient_BuildDynatraceVirtualService(t *testing.T) { os.Setenv(k8sutil.WatchNamespaceEnvVar, DefaultTestNamespace) - buffer := istio.BuildVirtualService("dt-vs", "ENVIRONMENTID.live.dynatrace.com", 443, "https") - vs := istiov1alpha3.VirtualService{} - err := json.Unmarshal(buffer, &vs) - if err != nil { - t.Errorf("Failed to marshal json %s", err) - } - ic := fakeistio.NewSimpleClientset(&vs) + vs := istio.BuildVirtualService("dt-vs", "ENVIRONMENTID.live.dynatrace.com", "https", 443) + ic := fakeistio.NewSimpleClientset(vs) vsList, err := ic.NetworkingV1alpha3().VirtualServices(DefaultTestNamespace).List(metav1.ListOptions{}) if err != nil { t.Errorf("Failed to create VirtualService in %s namespace: %s", DefaultTestNamespace, err) diff --git a/pkg/controller/oneagent/oneagent_controller.go b/pkg/controller/oneagent/oneagent_controller.go index 4a5969d0..2ba1e181 100644 --- a/pkg/controller/oneagent/oneagent_controller.go +++ b/pkg/controller/oneagent/oneagent_controller.go @@ -275,7 +275,10 @@ func (r *ReconcileOneAgent) reconcileVersion(reqLogger logr.Logger, instance *dy // determine pods to restart podsToDelete, instances := getPodsToRestart(podList.Items, dtc, instance) - if !reflect.DeepEqual(instances, instance.Status.Items) { + + // Workaround: 'instances' can be null, making DeepEqual() return false when comparing against an map instance. + // So, compare as long there is data. + if (len(instances) > 0 || len(instance.Status.Items) > 0) && !reflect.DeepEqual(instances, instance.Status.Items) { reqLogger.Info("oneagent pod instances changed") updateCR = true instance.Status.Items = instances diff --git a/version/version.go b/version/version.go index 9e82f646..2d987f27 100644 --- a/version/version.go +++ b/version/version.go @@ -1,5 +1,5 @@ package version var ( - Version = "v0.4.0" + Version = "v0.4.1" )