Creating a Runbook for Discovery

Create a runbook to scan and identify Apache Tomcat homes installed on resources in Fleet Application Management.

  1. Create a runbook to discover of Apache Tomcat homes.
    Provide basic information such as the runbook name (Apache Tomcat Discovery), select the Apache Tomcat custom product, the lifecycle operation (Discovery), and the required operating system (Linux.)

    Add parallel or rolling resource containers depending on how you want to want the task execution to be run across resources and configure them.

  2. Add a task to the runbook.
    Note

    Be sure to select Mark this as discovery output task.
    This action identifies the target outcome task, indicating to Fleet Application Management that the response of the task needs to be read and interpreted for software inventory collection.
  3. Upload the runbook task script from the file system or Object Storage. See Sample YAML for Discovery or Sample JSON for Discovery.
    The script should capture information such as product home or target path, product version, installed patches (if any), and the Java home and its version. The script should output the findings in a JSON format as provided by the downloadable template.
    For example:
    • The script details can be as follows: Object Storage > compartment: mycompartment > my_bucket > apache_tomcat_discovery.zip (several such files)
    • The Command field can be as follows: unzip -o -q apache_tomcat_discovery.zip; chmod +x apache_tomcat_discovery.py; python apache_tomcat_discovery.py

    For an example of the discovery script of apache_tomcat_discovery.py, see sample script for discovery.

You now have the runbook with tasks that discovers Apache Tomcat homes.

Sample Script for Discovery of a Product

Here's a sample Python script for the discovery of Apache Tomcat.
import json
import os
import subprocess
import datetime


class TOMCAT:

    def _get_all_tomcats(self):
        command = ['find', '/', '-type', 'd', '-name', 'webapps']
        sp = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        tomcat_paths = sp.stdout.decode("utf-8").strip().replace('/webapps', '').split('\n')

        #tomcat_paths=[path for path in tomcat_paths if not 'backup' in path]

        return tomcat_paths

    def _get_details(self, path):
        tomcat_details = dict()

        try:
            command = f'{path}/bin/version.sh'
            sp = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout, stderr = sp.communicate(timeout=10)
            info_list = stdout.decode("utf-8")

            for line in info_list.splitlines():
                if ':' in line:
                    key, value = line.split(':', 1)
                    tomcat_details[key.strip()] = value.strip()

            return tomcat_details

        except Exception as E:
           pass

    def _get_timestamp(self, file_path):
        if os.path.exists(file_path):
            timestamp = os.path.getmtime(file_path)
            modified_date = datetime.datetime.fromtimestamp(timestamp).strftime("%Y-%d-%m %H:%M:%S")
            return modified_date

    def _get_java_details(self):
        try:
            java_details = dict()
            command = "java -version 2>&1 | head -n 1"
            sp = subprocess.run(command, shell=True, stdout=subprocess.PIPE)
            java_version = sp.stdout.decode("utf-8").split('"')[1]

            # Getting Java Home
            command = "java -XshowSettings:properties -version 2>&1    | sed '/^[[:space:]]*java\.home/!d;s/^[[:space:]]*java\.home[[:space:]]*=[[:space:]]*//'"
            sp = subprocess.run(command, shell=True, stdout=subprocess.PIPE)
            java_home = sp.stdout.decode("utf-8").replace("\n", '')

            java_details['java_home'] = java_home
            java_details['java_version'] = java_version.split('_')[0]

            return java_details

        except Exception as E:
            pass

    def _instance(self, path, new_version_exists):
        properties = []
        installed_patches = []
        tomcat_details = self._get_details(path)

        instance = {"product": "Apache Tomcat"}
        instance.update({"version": '.'.join(tomcat_details['Server number'].split('.')[:2])})
        instance.update({"target_name": path})
        instance.update({"resource_name": ""})
        instance.update({"components": []})
        instance.update({"available_patches": []})

        if new_version_exists:
            installed_patches = [
                {
                    "patch_name": tomcat_details['Server number'],
                    "patch_applied_dt": self._get_timestamp(path),
                    "patch_description": tomcat_details['Server number'],
                    "patch_type":"Critical Patch Update",
                    "released_date":self._get_timestamp(path),
                    "severity":"CRITICAL"
                }
            ]

        else:
            installed_patches = [
                {
                    "patch_name": tomcat_details['Server number'],
                    "patch_applied_dt": self._get_timestamp(path),
                    "patch_description": tomcat_details['Server number'],
                    "patch_type": "Critical Patch Update"

                }
            ]

        instance.update({"installed_patches": installed_patches})

        for key, value in self._get_java_details().items():
            properties.append({"property_name": key, "property_value": value})

        instance.update({"properties": properties})

        return instance

    def _discovery_tomcat(self):
        targets = []
        tomcat_paths = self._get_all_tomcats()
        new_version_exists = any(['backup' in path for path in tomcat_paths])

        for path in tomcat_paths:
            if not 'backup' in path:
                targets.append(self._instance(path, new_version_exists))

        discovery_output = ({"targets": targets})

        return discovery_output


if __name__ == "__main__":
    SCRIPTS_DIR = "/opt/fams/.scripts"
    os.makedirs(SCRIPTS_DIR, exist_ok=True)
    tomcat = TOMCAT()
    tomcat_output = tomcat._discovery_tomcat()

    json_obj = json.dumps(tomcat_output, indent=4)
    print(json_obj)

    with open("{}/tomcat_discovery.json".format(SCRIPTS_DIR), 'wb') as outfile:
        outfile.write(json_obj.encode())

Sample JSON for Discovery

Here's a sample JSON for the discovery of Apache Tomcat.

{
  "compartmentId": "<your_root_compartment_ocid>",
  "displayName": "Apache Tomcat Discovery",
  "description": "Runbook to discovery Apache Tomcat Product Homes on an instance",
  "operation": "DISCOVERY",
  "runbookRelevance": "PRODUCT",
  "platform": "Apache Tomcat",
  "isDefault": false,
  "osType": "LINUX",
  "estimatedTime": "1",
  "associations": {
    "groups": [
      {
        "name": "Parallel_resource_container",
        "type": "PARALLEL_RESOURCE_GROUP",
        "properties": {
          "actionOnFailure": "ABORT",
          "condition": null
        }
      }
    ],
    "tasks": [
      {
        "stepName": "Apache_Tomcat_discovery_task",
        "associationType": "TASK",
        "taskRecordDetails": {
          "scope": "LOCAL",
          "executionDetails": {
            "executionType": "SCRIPT",
            "variables": null,
            "content": {
              "sourceType": "OBJECT_STORAGE_BUCKET",
              "namespaceName": "mytenancynamespace",
              "bucketName": "demo_bucket",
              "objectName": "my_apache_tomcat_discovery.zip",
              "checksum": "APLIeko3yTq4CXNWzxcVKvHg=="
            },
            "command": "unzip -o -q my_apache_tomcat_discovery.zip; chmod +x apache_tomcat_discovery.py ; python apache_tomcat_discovery.py",
            "credentials": []
          },
          "description": null,
          "platform": "Apache Tomcat",
          "isCopyToLibraryEnabled": false,
          "osType": "LINUX",
          "properties": {
            "numRetries": 0,
            "timeoutInSeconds": 3000
          },
          "isDiscoveryOutputTask": true,
          "isApplySubjectTask": false,
          "name": "Apache Tomcat_discovery_task"
        },
        "stepProperties": {
          "actionOnFailure": "ABORT",
          "condition": null
        },
        "outputVariableMappings": []
      }
    ],
    "executionWorkflowDetails": {
      "workflow": [
        {
          "groupName": "Parallel_resource_container",
          "type": "PARALLEL_RESOURCE_GROUP",
          "steps": [
            {
              "type": "TASK",
              "stepName": "Apache_Tomcat_discovery_task"
            }
          ]
        }
      ]
    }
  }
}

Sample YAML for Discovery

Here's a sample YAML for the discovery of Apache Tomcat.

compartmentId: <your_root_compartment_ocid>
displayName: Apache Tomcat Discovery
description: Runbook to discovery Apache Tomcat Product Homes on an instance
operation: DISCOVERY
runbookRelevance: PRODUCT
platform: Apache Tomcat
isDefault: false
osType: LINUX
estimatedTime: "1"
associations:
  groups:
    - name: Parallel_resource_container
      type: PARALLEL_RESOURCE_GROUP
      properties:
        actionOnFailure: ABORT
        condition: null
  tasks:
    - stepName: Apache_Tomcat_discovery_task
      associationType: TASK
      taskRecordDetails:
        scope: LOCAL
        executionDetails:
          executionType: SCRIPT
          variables: null
          content:
            sourceType: OBJECT_STORAGE_BUCKET
            namespaceName: mytenancynamespace
            bucketName: demo_bucket
            objectName: my_apache_tomcat_discovery.zip
            checksum: APLIeko3yTq4CXNWzxcVKvHg==
          command: unzip -o -q my_apache_tomcat_discovery.zip; chmod +x
            apache_tomcat_discovery.py ; python apache_tomcat_discovery.py
          credentials: []
        description: null
        platform: Apache Tomcat
        isCopyToLibraryEnabled: false
        osType: LINUX
        properties:
          numRetries: 0
          timeoutInSeconds: 3000
        isDiscoveryOutputTask: true
        isApplySubjectTask: false
        name: Apache Tomcat_discovery_task
      stepProperties:
        actionOnFailure: ABORT
        condition: null
      outputVariableMappings: []
  executionWorkflowDetails:
    workflow:
      - groupName: Parallel_resource_container
        type: PARALLEL_RESOURCE_GROUP
        steps:
          - type: TASK
            stepName: Apache_Tomcat_discovery_task