# CD Agent for Java Application

## Onboarding the Java CD Agent <a href="#sealightscdagentforjavaapplication-onboardingthejavacdagent" id="sealightscdagentforjavaapplication-onboardingthejavacdagent"></a>

These steps outline the onboarding steps needed on the environment, with the CD agent, added to each component that builds up the Application Under Test.

Each component within the application is a service running on a ‘dedicated’ JVM:

* This could be an application server like Tomcat, JBoss, Websphere/Weblogic, or a standalone Java process using the Java Runtime Environment.
* They can be on physical machines, VMs, containers, on-prem, or the cloud.

### Configuration steps <a href="#sealightscdagentforjavaapplication-configurationsteps" id="sealightscdagentforjavaapplication-configurationsteps"></a>

1. **Download an Agent Token (**[generating-a-token](https://docs.sealights.io/knowledgebase/setup-and-configuration/getting-started/steps-for-successful-onboarding/generating-a-token "mention")) **from the dashboard** and make it available to each component configured with our agent.
   * This can be done by placing it in a file accessible to the agent or through an environment variable directly or through a secret manager.
2. **Download the CD agent** and make it available to each component by copying it in, downloading it during startup, or mounting an external volume containing the agent.
   * The agent is downloadable from the following URL: <https://agents.sealights.co/sl-cd-agent/sl-cd-agent-latest.zip>
   * You can refer to the following sample commands below ([#sealightscdagentforjavaapplication-downloadingtheagent](#sealightscdagentforjavaapplication-downloadingtheagent "mention")).&#x20;
3. **Optional (required only when onboarding multiple services into a single Integration Build):**\
   Create an “Integration Build Lab ID” entry of type “CD only” in the dashboard for the tested application (see picture on the below).
   * Do so in the settings of the SeaLights dashboard, under '**Cockpit & Onboarding** → **Integration Build Labs** → **CD Only**'
   * The lab ID from this integration build entry needs to be provided to the CD agent through an environment variable.\ <img src="https://4057366433-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FAjqTCMRYvHhDgsdPLUnc%2Fuploads%2FTCLgg8s4dGfRl43xPoAQ%2Fimage.png?alt=media&#x26;token=045e286a-4f77-4c0a-8640-94d9ba018eb4" alt="" data-size="original">
4. **Add the CD agent to your JVM** as a `javaagent`.
   * This is done by updating the JVM parameters of the component with `-javaagent:sl-cd-agent.jar` (See samples below)
5. **Set the relevant environment variables to be used by your component JVM**, either each on its own before spinning up the JVM or through the JVM parameters themselves (using `-Dsl.` prefix) (See samples below)

{% hint style="success" %}
When the **application is up** and running and the **Sealights CD Agent configured**, you can see it is properly running from the ***Cockpit -> Live Agents Monitor*** screen.\
You have the ability to validate the JVM parameters in use with your application via the following command:

* Linux:  `ps -ef | grep java`
* Windows: `gwmi -Class Win32_Process -Filter "name like '%java%'" | Format-Table -Wrap -Property ProcessId, CommandLine` (Powershell prompt)
  {% endhint %}

### Agent’s Parameters Reference <a href="#sealightscdagentforjavaapplication-agentsparametersreference" id="sealightscdagentforjavaapplication-agentsparametersreference"></a>

#### Mandatory parameters <a href="#sealightscdagentforjavaapplication-mandatoryparameters" id="sealightscdagentforjavaapplication-mandatoryparameters"></a>

<table><thead><tr><th width="131.13153076171875">Property</th><th width="106.3333740234375">Required</th><th>Description</th></tr></thead><tbody><tr><td><strong>sl.token</strong><br>or<br><strong>sl.tokenFile</strong></td><td>Yes</td><td><p>The agent token to use for the secure connection, either as a parameter or in a file</p><p><strong>Note!</strong> The token can also be placed in a file called sltoken.txt alongside the agent and then this parameter is not required.</p></td></tr><tr><td><strong>sl.appName</strong></td><td>Yes</td><td>Name of the component</td></tr><tr><td><strong>sl.labId</strong></td><td>Yes</td><td>The labId generated for the Integration Build entry in Step #3, or a unique, hard-coded free-text labId when not using an Integration Build.</td></tr><tr><td><strong>sl.buildName</strong><br>or<br><strong>sl.buildNameLocation</strong></td><td>Yes</td><td><p>Name of the components version</p><p>sl.buildNameLocation value should be: <code>FILE_TYPE;./file/location/props.txt;key</code><br>it consists of three parts separated by a colon (;) character:</p><ul><li>FILE_TYPE - MANIFEST or PROPS</li><li>./file/location/props.txt - the absolute or relative path of the file</li><li>key - The name of the key, under which the build name is located</li></ul><p>If you have multiple different components under the same JVM, they get deployed independently. This means the build name should include all of them, you can configure each one with a separate build name location flag with the following naming convention: <code>sl.buildNameLocation_{appName}</code></p><p><strong>Note!</strong> The exact same value must be provided for the same version of the service being deployed multiple times<br>Recommendation: The buildname should allow you to trace back the service’s changes in your SCM. ex. the buildname comes from the Jenkin’s deployment job that shows the artifact version, which can be used to get SCM commit hash. This is useful when identifying changes identified in TGA report to those who made the changes for example.</p></td></tr><tr><td><strong>sl.includes</strong></td><td>Yes</td><td><p>Comma-separated list of search patterns with wildcards ( <code>*</code> = any string, <code>?</code> = any character) for the packages to be included in the scan. For example: <code>'com.example.*,io.*.demo,com.?ello.world'</code></p><p><strong>Note!</strong> You should prepend each of the enlisted packages with an asterisk sign (e.g., <code>-Dsl.includes=*com.example.*</code>) when you are running the application with the servlet container (e.g., Tomcat), or when the deployed configuration contains classes exploded from the java archive. </p></td></tr></tbody></table>

#### Optional parameters <a href="#sealightscdagentforjavaapplication-optionalparameters" id="sealightscdagentforjavaapplication-optionalparameters"></a>

These parameters may be required due to your specific configuration or environment’s limitations (e.g., proxy).

<table><thead><tr><th width="141.2904052734375">Property</th><th width="105.954345703125">Required</th><th>Description</th></tr></thead><tbody><tr><td><strong>sl.excludes</strong></td><td>No</td><td>Comma-separated list of search patterns with wildcards ( <code>*</code> = any string, <code>?</code> = any character) for the packages to be excluded in the scan. For example: <code>'com.example.*,io.*.demo,com.?ello.world'</code></td></tr><tr><td><strong>sl.branchName</strong></td><td>No</td><td>Component branch name. Defaults to <code>unspecified</code> if not provided.</td></tr><tr><td><strong>sl.workspace</strong></td><td>No</td><td>Folders to search for files to be scanned. Default is the current working directory</td></tr><tr><td><strong>sl.filesincluded</strong></td><td>No</td><td><p>Comma-separated list of search patterns with wildcards for the files to be included in the scan. Default is <code>*.class,*.jar,*.war,*.ear</code></p><p><strong>Note!</strong> Each file is handled with its full path, therefore an asterisk must be provided at the beginning unless specifying the full path in the value</p></td></tr><tr><td><strong>sl.filesexcluded</strong></td><td>No</td><td><p>Comma-separated list of search patterns with wildcards for the files to be excluded from the scan</p><p><strong>Note!</strong> Each file is handled with its full path, therefore an asterisk must be provided at the beginning unless specifying the full path in the value</p></td></tr><tr><td><strong>sl.recursive</strong></td><td>No</td><td>Indication for scanning the workspace paths recursively. The default value is <code>true</code>.</td></tr><tr><td><strong>sl.proxy</strong></td><td>No</td><td>Proxy for the agent to go through when communicating with SeaLights.</td></tr><tr><td><strong>sl.tags</strong></td><td>No</td><td>Free text comma-separated tags to help identify the agents later in the cockpit</td></tr></tbody></table>

\
**Environment Variables**

to Provide the Token to agent agent Using an Environment Variable, you can set `SL_TOKEN` to your Agent Token .

{% code overflow="wrap" lineNumbers="true" %}

```sh
export SL_TOKEN="IkjKdsf..."
```

{% endcode %}

#### Logging parameters <a href="#sealightscdagentforjavaapplication-loggingparameters" id="sealightscdagentforjavaapplication-loggingparameters"></a>

To enable logs, you can set the following parameters as environment variables or add them as `-Dsl.*` parameters. Both console output and file options are compatible and non-exclusive.

For logging into the console, add

{% code overflow="wrap" lineNumbers="true" %}

```sh
-Dsl.log.toConsole=true -Dsl.log.level=info [--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED]
```

{% endcode %}

For logging into a file, add

{% code overflow="wrap" lineNumbers="true" %}

```sh
-Dsl.log.toFile=true -Dsl.log.level=info -Dsl.log.folder=<path/with/permissions/> [--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED] [-Dsl.log.count=<value>] [-Dsl.log.limit=<arg>] [-Dsl.log.filename=<arg>]
```

{% endcode %}

<table><thead><tr><th width="189.3333740234375">Parameter</th><th width="92.9998779296875">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>sl.log.level</code></td><td>No</td><td>Sets the log level to one of the following: "off", "error", "warn", "info", "debug"</td></tr><tr><td><code>sl.log.toConsole</code></td><td>No</td><td>Set to true to enable log output to the console</td></tr><tr><td><code>sl.log.toFile</code></td><td>No</td><td>Set to true to enable log output to a file</td></tr><tr><td><code>sl.log.folder</code></td><td>No</td><td>Provide a folder to save the log files in</td></tr><tr><td><code>sl.log.filename</code></td><td>No</td><td>Provide the name of the log file</td></tr><tr><td><code>sl.log.count</code></td><td>No</td><td>Limit the number of log files to create. Default: 10</td></tr><tr><td><code>sl.log.limit</code></td><td>No</td><td>Limit the size of the log file in megabytes (MB). The default value is 10 (i.e. 10*1024 KB)</td></tr><tr><td><code>--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED</code></td><td>No</td><td>Special JVM parameter to allow logging in Java 9 and later in addition to <code>-Dsl.log.*</code> options above. <br>If the option is not provided, the test listener will work as usual, but logging will not work.</td></tr></tbody></table>

## Sample Commands <a href="#sealightscdagentforjavaapplication-samplecommands" id="sealightscdagentforjavaapplication-samplecommands"></a>

### Downloading the agent <a href="#sealightscdagentforjavaapplication-downloadingtheagent" id="sealightscdagentforjavaapplication-downloadingtheagent"></a>

The agent is downloadable from the following URL: <https://agents.sealights.co/sl-cd-agent/sl-cd-agent-latest.zip>

You can use the following commands to automate the process

{% code overflow="wrap" lineNumbers="true" %}

```sh
wget -nv  https://agents.sealights.co/sl-cd-agent/sl-cd-agent-latest.zip
unzip -oq sl-cd-agent-latest.zip
echo "Sealights CD Agent version used is:" `cat version.txt`
```

{% endcode %}

### Configuration commands <a href="#sealightscdagentforjavaapplication-configurationcommands" id="sealightscdagentforjavaapplication-configurationcommands"></a>

{% tabs %}
{% tab title="JRE" %}
{% code overflow="wrap" lineNumbers="true" %}

```sh
java -javaagent:/sealights/sl-cd-agent.jar -Dsl.token=${SL_TOKEN} -Dsl.appName=microservices_orders -Dsl.buildName=weaveworksdemos/carts:0.4.8 -Dsl.tags=JRE -Dsl.labId=integ_test_microservices -Dsl.includes="works*" -jar app.jar
```

{% endcode %}
{% endtab %}

{% tab title="BASH" %}
{% code overflow="wrap" lineNumbers="true" %}

```sh
export JAVA_TOOL_OPTIONS="-javaagent:/sealights/sl-cd-agent.jar -Dsl.tokenFile=/sealights/sltoken.txt -Dsl.appName=microservices_orders -Dsl.buildName=weaveworksdemos/carts:0.4.8 -Dsl.tags=bash -Dsl.labId=integ_test_microservices -Dsl.includes=works*"

java -jar app.jar
```

{% endcode %}
{% endtab %}

{% tab title="Docker compose" %}
{% code overflow="wrap" lineNumbers="true" %}

```yaml
  queue-master:
    image: weaveworksdemos/queue-master:0.3.1
    hostname: queue-master
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    restart: always
    cap_drop:
      - all
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    tmpfs:
      - /tmp:rw,noexec,nosuid
    environment:
      - JAVA_OPTS=-javaagent:/sealights/sl-cd-agent.jar -Dsl.tokenFile=/sealights/sltoken.txt -Dsl.appName=microservices_queuemaster -Dsl.buildName=${BUILD_NAME} -Dsl.tags=script,container -Dsl.labId=integ_test_microservices -Dsl.includes=works*
    volumes:
      - /tmp/sealights:/sealights
```

{% endcode %}

A sample to use `${BUILD_NAME}` dynamically is to set it in the `.env` file:

{% code overflow="wrap" lineNumbers="true" %}

```sh
BUILD_NAME=weaveworksdemos/queue-master:0.3.1
```

{% endcode %}
{% endtab %}

{% tab title="K8s using an init container" %}
{% code overflow="wrap" lineNumbers="true" %}

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: carts
  labels:
    name: carts
  namespace: sock-shop
spec:
  replicas: 1
  selector:
    matchLabels:
      name: carts
  template:
    metadata:
      labels:
        name: carts
    spec:
      initContainers:
      - name: java-cd-agent
        image: java-cd-agent:latest
        imagePullPolicy: Never
        command: ["/bin/sh", "-c", "cp /download/sl-cd-agent.jar /sealights"]
        volumeMounts:
          - mountPath: /sealights
            name: java-cd-agent-file
      containers:
      - name: carts
        image: weaveworksdemos/carts:0.4.8
        env:
        - name: JAVA_TOOL_OPTIONS
          value: -javaagent:/sealights/sl-cd-agent.jar -Dsl.tokenFile=/etc/sltoken.txt -Dsl.appName=microservices_carts -Dsl.buildName=${BUILD_NAME} -Dsl.tags=k8s,ic -Dsl.labId=integ_test_microservices -Dsl.includes=works* -Dsl.workspace=/path/to/app/folder/
        - name: JAVA_OPTS
          value: -Xms64m -Xmx128m -XX:+UseG1GC -Djava.security.egd=file:/dev/urandom -Dspring.zipkin.enabled=false
        resources:
          limits:
            cpu: 300m
            memory: 500Mi
          requests:
            cpu: 100m
            memory: 200Mi
        ports:
        - containerPort: 80
        securityContext:
          runAsNonRoot: true
          runAsUser: 10001
          capabilities:
            drop:
              - all
            add:
              - NET_BIND_SERVICE
          readOnlyRootFilesystem: true
        volumeMounts:
        - mountPath: /tmp
          name: tmp-volume
        - mountPath: /sealights
          name: java-cd-agent-file
      volumes:
      - name: tmp-volume
        emptyDir:
          medium: Memory
      - name: java-cd-agent-file
        emptyDir: {}
      nodeSelector:
        beta.kubernetes.io/os: linux
```

{% endcode %}

A sample to use `${BUILD_NAME}` dynamically is to set it using `envsubst`

{% code overflow="wrap" lineNumbers="true" %}

```sh
export BUILD_NAME=weaveworksdemos/carts:0.4.8
envsubst < k8s.yaml | kubectl apply -f -
```

{% endcode %}

Docker file for `java-cd-agent`

{% code overflow="wrap" lineNumbers="true" %}

```docker
FROM alpine:3.17.0
ADD sl-cd-agent.jar /download/sl-cd-agent.jar
```

{% endcode %}
{% endtab %}
{% endtabs %}
