Note:


Automate Patching for Apache Tomcat or a Third-Party Technology with OCI Fleet Application Management

Introduction

Oracle Cloud Infrastructure (OCI) Fleet Application Management service enables IT teams to automate software discovery and patch operations for any software deployed in OCI. The service provides prebuilt runbooks for discovering and patching Oracle technologies, including Oracle WebLogic Server, Oracle Linux, and more. Also, the custom runbooks and Bring Your Own Product capabilities enable you to define your product or technologies to be automatically discovered and patched by the service.

In this tutorial, we are using Apache Tomcat as an example of a popular third-party technology you might often need to patch. The following sections provide step-by-step instructions and reusable code samples to guide you on adding Apache Tomcat to be automatically discovered and applying patches using OCI Fleet Application Management. You can use the same process for any third-party product you want to patch with the service.

Note: We are describing the process using the OCI Console, but you can also use the Oracle Cloud Infrastructure Command Line Interface (OCI CLI) or API. For information about OCI Fleet Application Management, see Fleet Application Management.

Get Started with Patching Apache Tomcat

The Bring Your Own Product capability facilitates the integration of new products within OCI Fleet Application Management, such as third-party software, technologies, or application components. This capability enables the centralization of patch compliance and other lifecycle operations across these various components by using the service.

Using Bring Your Own Product capability, you will first create your custom product in the service along with its compliance policy, and available patches. Next, using custom runbooks, you will create both the discovery and the patching runbooks, enabling you to automate compliance management moving forward.

Objectives

Task 1: Create a Product

  1. Log in to the OCI Console, navigate to Observability & Management, and select Fleet Application Management.

  2. Click Administration.

  3. Under Metadata management, click Products and Create product.

    Product Creation 1

  4. Enter the following information for the new product.

    • Product Name: Enter the product name, avoiding any confidential information such as keys, and so on.
    • Version(s): Enter the version.
    • Patch Types (Optional): Select the patch type.
    • Compatible products (Optional): Add compatible products.
    • Components (Optional): Select components.
    • Credential names (Optional): Select the credential name.

    Product Creation 2

Task 2: Define a Patch Compliance Policy Rule

A software patch compliance policy is created automatically for each new product. The default policy does not contain any policy rules. You can edit the policy to add rules to specify the condition to evaluate if a specific target is compliant (if true) or non-compliant (else). You can use various product attributes to define the rules, such as product version, patch type, patch severity, patch selection criteria, and grace period. The patch compliance status is reported as indeterminate if you do not create policy rules.

  1. Go to the OCI Console, navigate to Administration, and click Compliance Policy.

  2. Select the compliance policy of the product you need to modify. (Syntax: Product name Compliance Policy).

  3. Click Create policy rule.

  4. Enter the product version and other attributes to be used in the condition.

    Compliance Policy Rule 1

    For example, the policy rules can have the following definition:

    • Rule name: Enter Apache Tomcat.
    • Product Version: Select 10.1 and above.
    • Patch type: Select Critical Patch.
    • Severity: Select CriticalPatch.
    • Patch selection: Select Patch Level.

    Compliance Policy Rule 2

Task 3: Create Patch Metadata and Upload the Patch

Create the patch metadata to make future patching easier for the product you have added. You should then upload the available patches to OCI Object Storage. Depending on the technology and the types of available patches for your new product, you can upload a generic patch or specific packages for different operating system configurations.

  1. Go to the OCI Console, navigate to Fleet Application Management, click Lifecycle Management, then Patches.

  2. Click Upload Patch.

  3. Enter the following information.

    • Patch name: Enter a name.
    • Product: Select a product.
    • Severity: Select a severity.
    • Select Dependent patches to specify the dependent patches that will be patched along with the current patch. For example, in case of Apache Tomcat, the following patch can be downloaded as apache-tomcat-10.1.25.tar.gz from here: Central Repository: org/apache/tomcat/tomcat/10.1.25.

    Upload Patch

Task 4: Create a Discovery Runbook for a Product

The service uses a discovery runbook to identify the software and version of the added product. For example, in the case of Apache Tomcat, the runbook script in Python for discovering and gathering details about Apache Tomcat instances on a system can be as follows:

Tasks in the Discovery Runbook Script

The script performs the following tasks:

Breakdown of Key Tasks

  1. Locate Apache Tomcat Instances.

  2. Extract Apache Tomcat version details.

    • Method (_get_details(path)):
      • Runs the version.sh script in the bin directory of each of the Apache Tomcat path.
      • Parses the output to extract key details (for example, version number) into a dictionary.
      • Handles errors: Any exceptions during the execution or parsing are silently ignored.
    • Output: Returns a dictionary of Apache Tomcat metadata (for example, server number).
  3. Retrieve file modification timestamp.

    • Method _get_timestamp(file_path):
      • Checks if a given file exists and retrieves its last modification time.
      • Formats the timestamp in dd-MMM-yyyy HH:mm:ss format.
    • Output: Returns the formatted timestamp.
  4. Gather Java environment details.

    • Method _get_java_details():
      • Uses system commands to fetch Java version and Java home path.
        • Java version: Obtained with java -version.
        • Java home path: Extracted from the java runtime properties.
    • Output: Returns a dictionary with java_version and java_home.
  5. Build a detailed instance dictionary.

    • Method _instance(path):
      • Constructs a dictionary representing a single Apache Tomcat instance.
        • Product details: Name, version, target path, and so on.
        • Installed patches: Includes version and last modified date of the directory.
        • Java properties: Includes java_version and java_home.
    • Output: Returns a structured dictionary for the Apache Tomcat instance.
  6. Discover and aggregate all instances.

    • Method _discovery_tomcat():
      • Calls _get_all_tomcats() to find Apache Tomcat paths.
      • Iterates over each path and calls _instance(path) to gather details.
      • Aggregates all instances into a targets list.
    • Output: Returns a dictionary with all discovered targets.
  7. Generate output.

    • Writes the discovered Apache Tomcat details to a JSON file.
      • Location: /opt/fams/.scripts/tomcat_discovery.json.
      • Format: Pretty-printed JSON.
    • Also prints the JSON object to the console for immediate visibility.

Script Flow

  1. Locate Apache Tomcat instances: The _get_all_tomcats() method scans the filesystem.

  2. Retrieve details for each instance: The _get_details() and _instance() methods extract relevant metadata.

  3. Collect Java details: The _get_java_details() method fetches the Java environment properties.

  4. Aggregate data: The _discovery_tomcat() method combines the information for all instances.

  5. Generate output: The results are saved in JSON format and printed.

    Example Output:

    {
    
        "targets": [
    
            {
                "product": "Tomcat",
                "version": "9.0",
                "target\_name": "/usr/local/tomcat",
                "resource\_name": "",
                "components": [],
                "available\_patches": [],
                "installed\_patches": [
                    {
                        "patch\_name": "9.0.50",
                        "patch\_applied\_dt": "19-Nov-2024 12:45:30",
                        "patch\_description": "",
                        "patch\_type": "",
                        "severity": ""
                    }
                ],
                "properties": [
                    {
                        "property\_name": "java\_home",
                        "property\_value": "/usr/lib/jvm/java-11-openjdk"
                    },
                    {
                        "property\_name": "java\_version",
                        "property\_value": "11"
                    }
                ]
            }
        ]
    }
    
  6. Error handling:

    • Silent failure for most exceptions (for example, missing files, command errors).
    • This approach prevents the script from terminating prematurely but might obscure errors during execution.

Example: Apache Tomcat Discovery Script in Python

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("%d-%b-%Y %H:%M:%S %z")
            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):
        properties = []
        tomcat\_details = self.\_get\_details(path)
        instance = {"product": "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": []})
        installed\_patches = [
            {
                "patch\_name": tomcat\_details['Server number'],
                "patch\_applied\_dt": self.\_get\_timestamp(path),
                "patch\_description": "",
                "patch\_type": "",
                "severity": ""
            }
        ]
        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()
        for path in tomcat\_paths:
            instances = targets.append(self.\_instance(path))
        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())

After handling all errors, the products are associated with a fleet or several fleets to automate discovery and operations. Once a product is on the list of allowed users for a fleet, its default discovery runbook will automatically find and update the software inventory with targets of the deployed product across all managed resources.

To create a runbook, follow the steps:

  1. Go to the OCI Console, navigate to Fleet Application Management, and click Actions and Controls.

  2. Click Runbooks and Create runbook.

  3. Enter Name, Description, Lifecycle operation, Runbook type, and select Operating System (OS) type and Estimated completion time.

    Runbook Creation 1

  4. Create your runbook by using the visual designer, upload a YAML or JSON file, or reference your existing automation script through Bash or Python script tasks within the runbook. For example, the sample provided is a runbook to discover Apache Tomcat.

    Runbook Creation 2

  5. For runbooks of type discovery, select Mark this as discovery output task to allow the service to read and parse the output of the task to populate the software inventory.

    Note: The service can parse the output only if the format of the output is based on the discovery output template.

    Discovery Output task

    The following is the JSON output (runbook\_Apache Tomcat\_discovery.json) for the product.

    {
      "id": "ocid1.famsrunbook.oc1.eu-frankfurt-1.xxxxxxxx",
      "displayName": "Apache Tomcat\_discovery",
      "description": null,
      "type": "USER\_DEFINED",
      "runbookRelevance": "PRODUCT",
      "operation": "DISCOVERY",
      "osType": "LINUX",
      "platform": "Apache Tomcat",
      "isDefault": false,
      "estimatedTime": "1",
      "lifecycleState": "INACTIVE",
      "lifecycleDetails": "{\"subState\":\"DRAFT\",\"message\":\"Draft runbook\"}",
      "timeCreated": "2024-11-19T13:03:20.376Z",
      "timeUpdated": "2024-11-19T13:03:20.376Z",
      "associations": {
        "tasks": [
          {
            "stepName": "Apache\_Tomcat\_discovery\_task",
            "associationType": "TASK",
            "taskRecordDetails": {
              "scope": "LOCAL",
              "executionDetails": {
                "executionType": "SCRIPT",
                "variables": null,
                "content": {
                  "sourceType": "OBJECT\_STORAGE\_BUCKET",
                  "namespaceName": "xxxxxx",
                  "namespaceName": "xxxxxx",
                  "bucketName": "demo\_bucket",
                  "objectName": "apache\_tomcat\_discovery\_demo.zip",
                  "checksum": "xxxxxxxxxxxxx"
                },
                "command": "unzip -o -q apache\_tomcat\_discovery\_demo.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": {
              "runOn": null,
              "condition": null,
              "actionOnFailure": "ABORT",
              "pauseDetails": null,
              "notificationPreferences": null
            },
            "outputVariableMappings": []
          }
        ],
        "groups": [
          {
            "type": "PARALLEL\_RESOURCE\_GROUP",
            "name": "Parallel\_resource\_container",
            "properties": {
              "runOn": null,
              "condition": null,
              "actionOnFailure": "ABORT",
              "pauseDetails": null,
              "notificationPreferences": null
            }
          }
        ],
        "executionWorkflowDetails": {
          "workflow": [
            {
              "groupName": "Parallel\_resource\_container",
              "type": "PARALLEL\_RESOURCE\_GROUP",
              "steps": [
                {
                  "type": "TASK",
                  "stepName": "Apache\_Tomcat\_discovery\_task"
                }
              ]
            }
          ]
        },
        "rollbackWorkflowDetails": null,
        "version": "1.0"
      },
      "compartmentId": "xxxxxx",
      "region": "xxxxxxx",
      "freeformTags": {},
      "definedTags": {
        "Oracle-Tags": {
          "CreatedBy": "xxxxxx",
          "CreatedOn": "2024-11-08T15:48:59.329Z"
        }
      },
      "systemTags": {}
    }
    
  6. Add more tasks to customize your runbook as needed.

    Edit Task

Task 5: Create a Runbook for Applying a Patch

Refer to Task 4 to create a custom runbook with your patching sequence.

After creating a product with its available patches and default discovery logic, you can now create a runbook for patching that includes the automation sequence specific to this technology and your organization’s IT process. Then, you will define a maintenance schedule to define when the runbook would be triggered to patch non-compliant targets that are identified in your fleet.

The Bash script (apache_tomcat_patching.sh) that automates the process of upgrading an Apache Tomcat installation is as follows. Also, you can find the tasks associated with the script.

  1. Initialize Variables

    • target_path: This extract from a target.json file in the DATA_DIR directory using jq.
    • patches_file: This variable can be used to dynamically identifies the latest patches.json file in the system.
    • patch_url: This specifies the directory for patches (/opt/fams/wls_patch).
  2. Display and Parse Patch Details: Read the content of the patches.json file for the following:

    • To extract the required patch version (required_version).
    • To determines the filename of the patch (file_name).
  3. Check Required Files

    • apache_tomcat_functions.sh:
      • Ensure the presence of a helper script (apache_tomcat_functions.sh).
      • If the file is missing, the script exits with an error.
    • Target Path Validation:
      • Verify that the target_path directory exists.
      • If it does not exist, the script exits with an error.
  4. Check the Current Version: Run Apache Tomcat’s version.sh script to fetch the currently installed version (curr_version).

  5. Prepare for an Upgrade

    • Back up Existing Installation: Call create_backup to back up the existing Apache Tomcat installation.
    • Stop Tomcat: Stop Apache Tomcat using a function (stop_tomcat).
  6. Upgrade Apache Tomcat Installation

    • Extract a New Version: Extract the new Apache Tomcat package (file_name) into the target directory.
    • Copy Configuration Files:
      • Copy critical files (for example, configuration, logs) from the old installation to a new one by using copy_main_files.
      • Handle errors during this step by restoring the backup.
    • Rename and Finalize: Rename the new directory to replace the old installation directory.
  7. Validate and Restart

    • Verify the Upgrade: Check the upgraded version by running version.sh again.
    • Restart Apache Tomcat: Start Apache Tomcat using start_tomcat.
  8. Handle Error

    • Provide meaningful error messages at various stages (for example, missing files, directory not found, upgrade failures).
    • Roll back changes if critical operations fail (for example, copying files or renaming directories).

Key Functions Used Are:

What Does It Accomplish?

The script provides a structured and automated approach for upgrading an Apache Tomcat instance, minimizing downtime, and ensuring a rollback mechanism in case of a failure. It relies on the predefined functions (apache_tomcat_functions.sh) to manage tasks such as stopping or starting Apache Tomcat and file handling.

The following is the sample Bash (apache\_tomcat\_patching.sh) script with the methods for applying patches.

\#
target\_path=$(cat ${DATA\_DIR}/target.json | jq -r '.target.target\_name')
patches\_file="$(find / -type f -name 'patches.json' | tail -1)"
patch\_url=/opt/fams/wls\_patch
\#
echo "Details of patches.json from path $patches\_file"
cat $patches\_file
required\_version=$(jq -r '.patches[0].name' $patches\_file)
file\_name=$(jq -r '.patches[0].location.object\_name' $patches\_file)
echo "Checking for tomcat\_functions.sh file "
if [ -f ./apache\_tomcat\_functions.sh ]; then
  source ./apache\_tomcat\_functions.sh
  echo -e "apache\_tomcat\_functions.sh file exists \n"
else
  echo "apache\_tomcat\_functions.sh file does not exist..Exiting"
  exit 1
fi
echo "Checking if Target Path $target\_path exists"
if [ ! -d "$target\_path" ]; then
  echo "$target\_path doesnt exist.....Exiting"
  exit 1
else
  echo "$target\_path exists"
fi
script\_dir=/opt/fams/.scripts/
echo "Target Directory: " $target\_path
echo "Target Version Download location: " $patch\_url
echo "Target Patch: " $required\_version
\# directories where tomcat is installed
curr\_version=$(sh $target\_path/bin/version.sh | grep 'Server number:' | awk '{print $3}')
echo "\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*"
tomcat\_vars
if [ $curr\_version != "" ]; then
  echo -e "Version $curr\_version is currently installed in Target Path $target\_path \n"
  dir\_path=$(basename "$target\_path") #old tomcat directory
  #file\_name=$(basename "$patch\_url")  #zip filename for new version
  #Stopping tomcat
  stop\_tomcat $target\_path
  #killing process
  #kill\_tomcat
  echo "\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*"
  echo -e "Upgrading Tomcat $curr\_version to patch $required\_version.................\n"
  # Backing old tomcat
  cd $target\_path/..
  create\_backup $dir\_path
  # Downloading New Tomcat Version
  #      echo -e "Downloading Tomcat version $required\_version.......................\n"
  #      download\_required\_version $patch\_url
  #      echo "\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*"
  #      # Extracting tomcat directories
  echo -e "Extracting Tomcat version from $file\_name file ......................."
  tar -xf "$patch\_url/$file\_name"
  echo -e "  COMPLETED : Extracted successfully \n"
  # Copying important files from old tomcat to new tomcat directories
  tomcat\_dir=$(basename "$file\_name" .tar.gz) # new tomcat directory
  echo -e "Copying important files from $dir\_path directory to $tomcat\_dir ......................."
  copy\_main\_files $backup\_dir $tomcat\_dir
  status=$?
  if [ $status -eq 0 ]; then
    # Renaming tomcat directory
    echo -e "Renaming $tomcat\_dir directory to $dir\_path......................."
    mv $tomcat\_dir $target\_path
  else
    echo -e "Process failed while Copying important files from $dir\_path directory to $tomcat\_dir.\n"
    mv $backup\_dir $dir\_path
    exit 1
  fi
  if [ $? -eq 0 ]; then
    upgraded\_version=$(sh $target\_path/bin/version.sh | grep 'Server number:' | awk '{print $3}')
    echo -e "  COMPLETED : Renaming directory \n"
    echo -e "Successfully upgraded tomcat to $upgraded\_version from $curr\_version \n"
    # Starting tomcat
    echo -e "Starting Tomcat......................."
    start\_tomcat $target\_path
  else
    echo -e "Process failed while renaming $tomcat\_dir directory to $target\_path.\n"
    exit 1
  fi
else
  echo -e "Required version is empty, Exiting \n"
  exit 1
fi
#done
stop\_tomcat(){
tomcat\_dir=$1
echo "Stopping Tomcat Service"
sh $tomcat\_dir/bin/shutdown.sh
}
start\_tomcat(){
tomcat\_dir=$1
echo "Starting Tomcat Service"
sh $tomcat\_dir/bin/startup.sh
}
kill\_tomcat(){
  myarray=( `ps aux | grep tomcat | awk '{print $2}'` )
  for i in "${myarray[@]}"
    do
      echo "Killing Process $i"
      kill -9 $i
  done
}
tomcat\_vars(){
\#  curr\_ver=$(jq --arg ident "$dir" -r '.targets[] | select(.target\_name == $ident) |.version' $script\_dir/tomcat\_discovery.json)
\#  echo "Current Version: "$curr\_version
  tomcat\_home=$(jq -r '.targets[].target\_name' $script\_dir/tomcat\_discovery.json)
  echo "Tomcat Home: "$tomcat\_home
}
create\_backup(){
  dir\_path=$1
\#  curr\_version=$2
  echo "  Backing up directory: $dir\_path"
  prefix=backup
  backup\_dir="${dir\_path}\_${prefix}"
  mkdir -p "$backup\_dir"
  cp -r  "$dir\_path"/\* "$backup\_dir"/
  if [ "$?" -eq 0 ]; then
    echo -e "  COMPLETED : Backup directory $backup\_dir created \n"
    rm -r "$dir\_path"
  fi
}
download\_required\_version(){
  download\_url=$1
  wget -nc $download\_url
}
copy\_main\_files(){
  old\_tomcat=$1
  new\_tomcat=$2
  cp -r ./$old\_tomcat/conf/\* ./$new\_tomcat/conf/
  cp -r ./$old\_tomcat/webapps/\*  ./$new\_tomcat/webapps/
  if [ "$?" -eq 0 ]; then
    echo -e "  COMPLETED : Copying files into directory \n"
    return 0  # Success
  else
    return 1  # Failure
  fi
}
copy\_rollback\_files(){
  old\_tomcat=$1
  new\_tomcat=$2
  cp -r $old\_tomcat/conf/\* /$new\_tomcat/conf/
  cp -r $old\_tomcat/webapps/\*  /$new\_tomcat/webapps/
  echo -e "  COMPLETED : Copying files into directory \n"
}
create\_rollback\_backup(){
  curr\_tomcat=$1
  rollback\_tomcat=$2
  echo "  Backing up directory: $dir\_path"
  prefix=$curr\_version
  backup\_dir="${curr\_tomcat}\_${prefix}"
  mkdir -p "$backup\_dir"
  cp -r  "$dir\_path"/\* "$backup\_dir"/
  echo -e "  COMPLETED : Backup directory $backup\_dir created \n"
  rm -r "$dir\_path"
}

Task 6: Create a Fleet

Create a fleet and get your product on the related allow list to discover its software inventory, know about the software patch compliance status, and fix the software patch compliance.

  1. Go to the OCI Console, navigate to Fleet Application Management, Fleets, and click Create Fleet.

  2. Enter the Name and Description for the fleet and add resources.

  3. Enable automatic confirmation of the target’s resources.

Task 7: Fix the Software Patch Compliance

Click Fix now to fix software patch compliance for a fleet on its details page or create a schedule from the Schedules page of Lifecycle management.

If you click Fix now, the compliance job will run in the next 15 minutes, whereas if you select the schedule option from the Schedules page, you can create a job for the future or set a recursive schedule. By defining a maintenance schedule, specify when the runbook would be triggered to patch non-compliant targets identified in your fleet.

Acknowledgments

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.