You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2022/01/19 07:59:34 UTC

[skywalking-showcase] branch main updated: Add Java agent injector feature (#14)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-showcase.git


The following commit(s) were added to refs/heads/main by this push:
     new 95e9576  Add Java agent injector feature (#14)
95e9576 is described below

commit 95e95766a266ae033b186b9fef3939d098d6e618
Author: dashanji <71...@users.noreply.github.com>
AuthorDate: Wed Jan 19 15:59:26 2022 +0800

    Add Java agent injector feature (#14)
---
 .github/workflows/go.yml                           | 43 +++++++++++
 Makefile.in                                        |  3 +
 deploy/platform/kubernetes/Makefile.in             |  2 +-
 .../kubernetes/feature-agent/resources.yaml        | 24 +++++--
 .../kubernetes/feature-single-node/resources.yaml  |  7 ++
 deploy/platform/kubernetes/features.mk             | 26 +++++++
 docs/readme.md                                     |  2 +-
 scripts/prepare-e2e.sh                             | 83 ++++++++++++++++++++++
 .../Makefile => scripts/wait-cert-manager-ready.sh | 49 +++++++++----
 services/load-gen/Makefile                         |  2 +-
 test/e2e/e2e.yaml                                  | 82 +++++++++++++++++++++
 test/e2e/kind.yaml                                 | 41 +++++++++++
 test/e2e/verify/service.yaml                       | 43 +++++++++++
 13 files changed, 387 insertions(+), 20 deletions(-)

diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
new file mode 100644
index 0000000..f6ecabe
--- /dev/null
+++ b/.github/workflows/go.yml
@@ -0,0 +1,43 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: Continuous Integration
+
+on: pull_request
+
+env:
+  IMAGE_HUB: ghcr.io/apache/skywalking-showcase
+  IMAGE_TAG: ${{ github.sha }}
+  TAG: ${{ github.sha }}
+
+jobs:
+  e2e-tests:
+    name: e2e tests(kubenretes platform)
+    runs-on: ubuntu-latest
+    steps:
+      - name: Install Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.17
+      - name: Check out source code
+        uses: actions/checkout@v2
+      - name: Build Docker Image
+        shell: bash
+        run: make docker -j 5
+      - name: Run E2E Test
+        uses: apache/skywalking-infra-e2e@996ed8902e941e2883fcf0ac5b3090364942d205
+        with:
+          e2e-file: test/e2e/e2e.yaml
diff --git a/Makefile.in b/Makefile.in
index 742c980..03ce498 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34,5 +34,8 @@ SW_EVENT_EXPORTER_IMAGE ?= ghcr.io/apache/skywalking-kubernetes-event-exporter/s
 SW_AGENT_NODEJS_BACKEND_VERSION ?= e755659c7f308d3b5589619778c8360308cb14f8
 SW_AGENT_NODEJS_FRONTEND_VERSION ?= af0565a67d382b683c1dbd94c379b7080db61449
 
+SWCK_OPERATOR_VERSION ?= 0.6.0
+CERT_MANAGER_VERSION ?= v1.3.1
+
 # ALL variables should be listed above ^^
 EXPORTED_VARS := $(filter-out <%,$(.VARIABLES))
diff --git a/deploy/platform/kubernetes/Makefile.in b/deploy/platform/kubernetes/Makefile.in
index 4a47a8e..9f5a1e8 100644
--- a/deploy/platform/kubernetes/Makefile.in
+++ b/deploy/platform/kubernetes/Makefile.in
@@ -21,4 +21,4 @@
 NAMESPACE ?= default
 AGENTLESS ?= false
 
-FEATURE_FLAGS ?= agent,cluster,kubernetes-monitor,so11y,vm,als,event,istiod-monitor
+FEATURE_FLAGS ?= java-agent-injector,cluster,kubernetes-monitor,so11y,vm,als,event,istiod-monitor
\ No newline at end of file
diff --git a/deploy/platform/kubernetes/feature-agent/resources.yaml b/deploy/platform/kubernetes/feature-agent/resources.yaml
index 2db14c1..9c578ac 100644
--- a/deploy/platform/kubernetes/feature-agent/resources.yaml
+++ b/deploy/platform/kubernetes/feature-agent/resources.yaml
@@ -44,16 +44,23 @@ spec:
   template:
     metadata:
       labels:
+        # @feature: java-agent-injector; enable the java agent injector
+        swck-java-agent-injected: "true"
         app: gateway
       annotations:
         sidecar.istio.io/inject: "${AGENTLESS}"
+        # @feature: java-agent-injector; set the java agent configuration
+        strategy.skywalking.apache.org/inject.Container: "gateway"
+        strategy.skywalking.apache.org/agent.Overlay: "true"
+        agent.skywalking.apache.org/agent.service_name: "agent::gateway"
     spec:
       containers:
         - name: gateway
           image: ${HUB}/gateway-service:${TAG}
-          imagePullPolicy: Always
+          imagePullPolicy: IfNotPresent
           ports:
             - containerPort: 80
+          # @feature: agent; set env to configure java agent, If we use injector, we don't need to set env, only to configure java gent through annotation
           env:
             - name: SW_AGENT_NAME
               value: agent::gateway
@@ -88,16 +95,23 @@ spec:
   template:
     metadata:
       labels:
+        # @feature: java-agent-injector; enable the java agent injector
+        swck-java-agent-injected: "true"
         app: songs
       annotations:
         sidecar.istio.io/inject: "${AGENTLESS}"
+        # @feature: java-agent-injector; set the java agent configuration
+        strategy.skywalking.apache.org/inject.Container: "songs"
+        strategy.skywalking.apache.org/agent.Overlay: "true"
+        agent.skywalking.apache.org/agent.service_name: "agent::songs"
     spec:
       containers:
         - name: songs
           image: ${HUB}/songs-service:${TAG}
-          imagePullPolicy: Always
+          imagePullPolicy: IfNotPresent
           ports:
             - containerPort: 80
+          # @feature: agent; set env to configure java agent, If we use injector, we don't need to set env, only to configure java gent through annotation
           env:
             - name: SW_AGENT_NAME
               value: agent::songs
@@ -139,7 +153,7 @@ spec:
       containers:
         - name: recommendation
           image: ${HUB}/recommendation-service:${TAG}
-          imagePullPolicy: Always
+          imagePullPolicy: IfNotPresent
           ports:
             - containerPort: 80
           env:
@@ -183,7 +197,7 @@ spec:
       containers:
         - name: app
           image: ${HUB}/app:${TAG}
-          imagePullPolicy: Always
+          imagePullPolicy: IfNotPresent
           ports:
             - containerPort: 80
           env:
@@ -216,4 +230,4 @@ spec:
       containers:
         - name: app
           image: ${HUB}/load-gen:${TAG}
-          imagePullPolicy: Always
+          imagePullPolicy: IfNotPresent
diff --git a/deploy/platform/kubernetes/feature-single-node/resources.yaml b/deploy/platform/kubernetes/feature-single-node/resources.yaml
index 05ba50f..24c1529 100644
--- a/deploy/platform/kubernetes/feature-single-node/resources.yaml
+++ b/deploy/platform/kubernetes/feature-single-node/resources.yaml
@@ -231,6 +231,13 @@ spec:
           imagePullPolicy: Always
           ports:
             - containerPort: 8080
+          readinessProbe:
+            httpGet:
+              path: /
+              port: 8080
+            initialDelaySeconds: 3
+            periodSeconds: 3
+            failureThreshold: 10
           env:
             - name: SW_OAP_ADDRESS
               value: http://oap:12800
diff --git a/deploy/platform/kubernetes/features.mk b/deploy/platform/kubernetes/features.mk
index eed2767..7aeb55f 100644
--- a/deploy/platform/kubernetes/features.mk
+++ b/deploy/platform/kubernetes/features.mk
@@ -81,3 +81,29 @@ undeploy.feature-kubernetes-monitor:
 	@kubectl delete --ignore-not-found -f https://raw.githubusercontent.com/kubernetes/kube-state-metrics/v2.2.4/examples/standard/cluster-role-binding.yaml
 	@kubectl delete --ignore-not-found -f https://raw.githubusercontent.com/kubernetes/kube-state-metrics/v2.2.4/examples/standard/service.yaml
 	@kubectl delete --ignore-not-found -f https://raw.githubusercontent.com/kubernetes/kube-state-metrics/v2.2.4/examples/standard/deployment.yaml
+
+# @feature: java-agent-injector; use the java agent injector to inject the java agent more natively
+.PHONY: feature-java-agent-injector
+feature-java-agent-injector:
+
+# @feature: java-agent-injector; the swck operator depends on the certificate management of the cert-manager
+.PHONY: install-cert-manager
+install-cert-manager:
+	@kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml
+	@sh ../../../scripts/wait-cert-manager-ready.sh
+
+# @feature: java-agent-injector; the java agent injector is a component of the swck operator, so we need to deploy the swck operator firstly
+.PHONY: deploy.feature-java-agent-injector
+deploy.feature-java-agent-injector: install-cert-manager
+	@curl -Ls https://archive.apache.org/dist/skywalking/swck/${SWCK_OPERATOR_VERSION}/skywalking-swck-${SWCK_OPERATOR_VERSION}-bin.tgz | tar -zxf - -O ./config/operator-bundle.yaml | kubectl apply -f -
+	@kubectl label namespace --overwrite $(NAMESPACE) swck-injection=enabled
+	# @feature: java-agent-injector; we can update the agent's backend address in a single-node cluster firstly so that we don't need to add the same backend env for every java agent
+	@kubectl get configmap skywalking-swck-java-agent-configmap -n skywalking-swck-system -oyaml | sed "s/127.0.0.1/$(NAMESPACE)-oap.$(NAMESPACE)/" | kubectl apply -f -
+	$(MAKE) deploy FEATURE_FLAGS=agent AGENTLESS=false SHOW_TIPS=false
+
+# @feature: java-agent-injector; uninstall the swck operator and cert-manager
+.PHONY: undeploy.feature-java-agent-injector
+undeploy.feature-java-agent-injector:
+	@curl -Ls https://archive.apache.org/dist/skywalking/swck/${SWCK_OPERATOR_VERSION}/skywalking-swck-${SWCK_OPERATOR_VERSION}-bin.tgz | tar -zxf - -O ./config/operator-bundle.yaml | kubectl delete -f -
+	@kubectl delete -f https://github.com/jetstack/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml
+	$(MAKE) undeploy FEATURE_FLAGS=agent AGENTLESS=false SHOW_TIPS=false
\ No newline at end of file
diff --git a/docs/readme.md b/docs/readme.md
index 1b648d2..3aba835 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -76,7 +76,7 @@ Currently, the features supported are:
 
 | Name          | Description | Note |
 | -----------   | ----------- | ----------- |
-| `agent`       | Deploy microservices with SkyWalking agent enabled. | The microservices include agents for Java, NodeJS server, browser, Python. |
+| `java-agent-injector`       | Use the java agent injector to inject the Skywalking Java agent and deploy microservices with other SkyWalking agent enabled. | The microservices include agents for Java, NodeJS server, browser, Python. |
 | `cluster`     | Deploy SkyWalking OAP in cluster mode, with 2 nodes, and SkyWalking RocketBot UI, ElasticSearch as storage. | Only one of `cluster` or `single-node` can be enabled. |
 | `single-node` | Deploy only one single node of SkyWalking OAP, and SkyWalking RocketBot UI, ElasticSearch as storage. | Only one of `cluster` or `single-node` can be enabled. |
 | `so11y`       | Enable SkyWalking self observability. | This is enabled by default for platform [Docker Compose](#docker-compose). |
diff --git a/scripts/prepare-e2e.sh b/scripts/prepare-e2e.sh
new file mode 100755
index 0000000..7aacb2a
--- /dev/null
+++ b/scripts/prepare-e2e.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+OS=$(go env GOOS)
+ARCH=$(go env GOHOSTARCH)
+
+INSTALL_DIR=/usr/local/bin
+
+TEMP_DIR=/tmp/skywalking-infra-e2e
+
+KUBECTL_VERSION=v1.19.1
+ISTIOCTL_VERSION=1.9.1
+SWCTL_VERSION=0.9.0
+
+prepare_ok=true
+# install kubectl
+function install_kubectl()
+{
+    if ! command -v kubectl &> /dev/null; then
+      curl -LO https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/${OS}/${ARCH}/kubectl && chmod +x ./kubectl && mv ./kubectl ${INSTALL_DIR}
+      if [ $? -ne 0 ]; then
+        echo "install kubectl error, please check"
+        prepare_ok=false
+      fi
+    fi
+}
+# install istioctl
+function install_istioctl()
+{
+    if ! command -v istioctl &> /dev/null; then
+      mkdir -p $TEMP_DIR && cd $TEMP_DIR
+      curl -L https://istio.io/downloadIstio | ISTIO_VERSION=${ISTIOCTL_VERSION} TARGET_ARCH=${ARCH} sh -
+      if [ $? -ne 0 ]; then
+        echo "install istioctl error, please check"
+        prepare_ok=false
+      fi
+      cp istio-${ISTIO_VERSION}/bin/istioctl $INSTALL_DIR
+    fi
+}
+
+# install swctl
+function install_swctl()
+{
+    if ! command -v swctl &> /dev/null; then
+      cd $TEMP_DIR && wget https://github.com/apache/skywalking-cli/archive/0.9.0.tar.gz -O - |\
+      tar xz && cd skywalking-cli-${SWCTL_VERSION} && make ${OS} && mv bin/swctl-*-${OS}-amd64 ${INSTALL_DIR}/swctl 
+      if [ $? -ne 0 ]; then
+        echo "install swctl error, please check"
+        prepare_ok=false
+      fi
+    fi
+}
+
+function install_all()
+{
+    echo "check e2e dependencies..."
+    install_kubectl
+    install_istioctl
+    install_swctl
+    if [ "$prepare_ok" = false ]; then
+        echo "check e2e dependencies failed"
+        exit
+    else
+        echo "check e2e dependencies successfully"
+    fi
+}
+
+install_all
\ No newline at end of file
diff --git a/services/load-gen/Makefile b/scripts/wait-cert-manager-ready.sh
similarity index 50%
copy from services/load-gen/Makefile
copy to scripts/wait-cert-manager-ready.sh
index c4ec4f3..2067170 100644
--- a/services/load-gen/Makefile
+++ b/scripts/wait-cert-manager-ready.sh
@@ -1,3 +1,5 @@
+#!/bin/bash
+
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -16,19 +18,42 @@
 # under the License.
 #
 
-include ../../Makefile.in
-
-.PHONY: build
-build:
+TIMEOUT=120
 
-.PHONY: docker docker.build docker.push
+MANIFEST=$(mktemp)
 
-docker: docker.build
+cat << EOF > $MANIFEST
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+  name: test-selfsigned
+  namespace: default
+spec:
+  selfSigned: {}
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  name: selfsigned-cert
+  namespace: default
+spec:
+  dnsNames:
+    - example.com
+  secretName: selfsigned-cert-tls
+  issuerRef:
+    name: test-selfsigned
+EOF
 
-docker.build:
-	docker build . -t $(HUB)/load-gen:$(TAG)
+( bash -c -- "\
+    while ! kubectl apply -f $MANIFEST 2> /dev/null; \
+    do \
+      sleep 0.1; \
+    done" ) & pid=$!
+( sleep $TIMEOUT && pkill -HUP $pid ) 2>/dev/null & watcher=$!
+if wait $pid 2>/dev/null; then
+    pkill -HUP -P $watcher
+    wait $watcher
+fi
 
-docker.push: docker.build
-	docker push $(HUB)/load-gen:$(TAG)
-	docker tag $(HUB)/load-gen:$(TAG) $(HUB)/load-gen:$(TAG)-agentless
-	docker push $(HUB)/load-gen:$(TAG)-agentless
+# make sure the dummy Issuer and Certificate will be deleted
+trap "kubectl delete -f $MANIFEST; rm $MANIFEST" 0 2 3 15
diff --git a/services/load-gen/Makefile b/services/load-gen/Makefile
index c4ec4f3..03eab0f 100644
--- a/services/load-gen/Makefile
+++ b/services/load-gen/Makefile
@@ -26,7 +26,7 @@ build:
 docker: docker.build
 
 docker.build:
-	docker build . -t $(HUB)/load-gen:$(TAG)
+	docker build . -t $(HUB)/load-gen:$(TAG) -t $(HUB)/load-gen:$(TAG)-agentless
 
 docker.push: docker.build
 	docker push $(HUB)/load-gen:$(TAG)
diff --git a/test/e2e/e2e.yaml b/test/e2e/e2e.yaml
new file mode 100644
index 0000000..4b4ea38
--- /dev/null
+++ b/test/e2e/e2e.yaml
@@ -0,0 +1,82 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+setup:
+  env: kind
+  file: ./kind.yaml
+  steps:
+    - name: prepare e2e.yaml
+      command: bash scripts/prepare-e2e.sh
+    - name: setup showcase
+      command: |
+        export KUBECONFIG=$TMPDIR/e2e-k8s.config
+        export PATH="$PATH:/tmp/skywalking-infra-e2e/istio-1.9.1/bin"
+        # the kind has only one node
+        sed -i 's/cluster/single-node/' deploy/platform/kubernetes/Makefile.in
+        sed -i 's/1000m/500m/' deploy/platform/kubernetes/feature-single-node/resources.yaml 
+        make deploy.kubernetes
+      wait:
+        - namespace: skywalking-swck-system
+          resource: pod
+          for: condition=Ready
+        - namespace: default
+          resource: pod
+          for: condition=Ready
+        - namespace: default-agentless
+          resource: pod
+          for: condition=Ready
+        - namespace: istio-system
+          resource: pod
+          for: condition=Ready
+  kind:
+    import-images:
+      - ${IMAGE_HUB}/gateway-service:${IMAGE_TAG}
+      - ${IMAGE_HUB}/gateway-service:${IMAGE_TAG}-agentless
+      - ${IMAGE_HUB}/songs-service:${IMAGE_TAG}
+      - ${IMAGE_HUB}/songs-service:${IMAGE_TAG}-agentless
+      - ${IMAGE_HUB}/recommendation-service:${IMAGE_TAG}
+      - ${IMAGE_HUB}/recommendation-service:${IMAGE_TAG}-agentless
+      - ${IMAGE_HUB}/app:${IMAGE_TAG}
+      - ${IMAGE_HUB}/app:${IMAGE_TAG}-agentless
+      - ${IMAGE_HUB}/load-gen:${IMAGE_TAG}
+      - ${IMAGE_HUB}/load-gen:${IMAGE_TAG}-agentless
+    expose-ports:
+      - namespace: default
+        resource: service/rocket-bot 
+        port: 8080
+  timeout: 20m
+
+cleanup:
+  # always never success failure
+  on: always
+
+trigger:
+  action: http
+  interval: 10s
+  times: 5
+  url: http://${service_rocket_bot_host}:${service_rocket_bot_8080}
+  method: GET
+
+verify:
+  # verify with retry strategy
+  retry:
+    # max retry count
+    count: 20
+    # the interval between two attempts, e.g. 10s, 1m.
+    interval: 30s
+  cases:
+    # test service
+    - query: swctl --display yaml --base-url=http://${service_rocket_bot_host}:${service_rocket_bot_8080}/graphql service ls
+      expected: ./verify/service.yaml
\ No newline at end of file
diff --git a/test/e2e/kind.yaml b/test/e2e/kind.yaml
new file mode 100644
index 0000000..fcb7a90
--- /dev/null
+++ b/test/e2e/kind.yaml
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# this config file contains all config fields with comments
+# NOTE: this is not a particularly useful config file
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+# patch the generated kubeadm config with some extra settings
+kubeadmConfigPatches:
+- |
+  apiVersion: kubelet.config.k8s.io/v1beta1
+  kind: KubeletConfiguration
+  evictionHard:
+    nodefs.available: "0%"
+# patch it further using a JSON 6902 patch
+kubeadmConfigPatchesJSON6902:
+- group: kubeadm.k8s.io
+  version: v1beta2
+  kind: ClusterConfiguration
+  patch: |
+    - op: add
+      path: /apiServer/certSANs/-
+      value: my-hostname
+# 1 control plane node
+nodes:
+# the control plane node config
+- role: control-plane
+  image: kindest/node:v1.19.1
+
diff --git a/test/e2e/verify/service.yaml b/test/e2e/verify/service.yaml
new file mode 100644
index 0000000..221fa49
--- /dev/null
+++ b/test/e2e/verify/service.yaml
@@ -0,0 +1,43 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+{{- contains . }}
+- id: {{ b64enc "agentless::gateway" }}.1
+  name: agentless::gateway
+  group: ""
+- id: {{ b64enc "agentless::songs" }}.1
+  name: agentless::songs
+  group: ""
+- id: {{ b64enc "agentless::recommendation" }}.1
+  name: agentless::recommendation
+  group: ""
+- id: {{ b64enc "agentless::app" }}.1
+  name: agentless::app
+  group: ""
+- id: {{ b64enc "agent::gateway" }}.1
+  name: agent::gateway
+  group: ""
+- id: {{ b64enc "agent::songs" }}.1
+  name: agent::songs
+  group: ""
+- id: {{ b64enc "agent::recommendation" }}.1
+  name: agent::recommendation
+  group: ""
+- id: {{ b64enc "agent::app" }}.1
+  name: agent::app
+  group: ""
+{{- end }}
\ No newline at end of file