IBM UrbanCode Deploy, also known as IBM DevOps Deploy, is a powerful tool for automating application deployments across various environments. It comes with an extensive range of built-in plugins, but many organizations find the need to develop custom plugins to meet their specific deployment requirements.
I am going to guide you through an end-to-end build of a custom IBM UCD plugin from the setup phase through deployment. During this time, we'll share best practices with you that would ensure integration as smooth as silk and optimization for your best plugin performance.
Why Develop Custom Plugins for IBM UrbanCode Deploy?
Custom plugins can extend IBM UCD beyond its default capabilities. Examples of use cases include integration with third-party tools, automating complex deployment tasks that have organisation-specific logic, and enforcing security compliance by making custom deployment policies.
Prerequisites for Custom Plugin Development
Before diving into development, ensure you have:
IBM UrbanCode Deploy installed (or access to a UCD server for testing).
Java Development Kit (JDK 8 or later).
Apache Maven for building the plugin.
A code editor or IDE (e.g., IntelliJ IDEA, Eclipse, or VS Code).
Familiarity with XML and Java.
Steps to Develop a Custom IBM UCD Plugin
๐๐ญ๐๐ฉ ๐: ๐๐๐ญ ๐๐ฉ ๐๐จ๐ฎ๐ซ ๐๐๐ฏ๐๐ฅ๐จ๐ฉ๐ฆ๐๐ง๐ญ ๐๐ง๐ฏ๐ข๐ซ๐จ๐ง๐ฆ๐๐ง๐ญ
Download the IBM UCD Plugin Development Kit (PDK) from the GitHub repository Download Custom PDK.
After downloading, extract the PDK and open the extracted directory in your preferred code editor. For this example, Iโll be using Visual Studio Code.
Project Structure
Custom-Plugin-Agent-Data-Parser/ โ โโโ pom.xml โ โโโ src/ โโโ main/ โโโ java/ โโโ com/ โโโ opensource/ โโโ GetAgentDetailsCustom.java
UCD Plugin Structure
Custom-Plugin-Agent-Data-Parser/ โโโ <maven-built>.jar โโโ plugin.xml โโโ info.xml โโโ upgrade.xml
๐๐ญ๐๐ฉ ๐: ๐๐๐๐ข๐ง๐ ๐ญ๐ก๐ ๐ฉ๐ฅ๐ฎ๐ ๐ข๐ง'๐ฌ ๐๐ฎ๐ง๐๐ญ๐ข๐จ๐ง๐๐ฅ๐ข๐ญ๐ฒ, ๐ข๐๐๐ง๐ญ๐ข๐๐ฒ ๐ซ๐๐ช๐ฎ๐ข๐ซ๐๐ ๐ข๐ง๐ฉ๐ฎ๐ญ๐ฌ, ๐๐ง๐ ๐๐๐ฌ๐ข๐ ๐ง ๐ญ๐ก๐ ๐ฉ๐ฅ๐ฎ๐ ๐ข๐ง.๐ฑ๐ฆ๐ฅ ๐๐จ๐ง๐๐ข๐ ๐ฎ๐ซ๐๐ญ๐ข๐จ๐ง.
plugin.xml It helps define essential information regarding the plugin, including its name and version, and also the actions that the plugin should carry out; it will also configure the plugin's dependencies and set the execution order of its steps here.
Identifying the Required Inputs and drafting a preliminary blueprint.
- For our IBM UCD Agent Data Parser plugin, we need a few pieces of information from the user. The inputs guarantee that the plugin will be able to connect to UCD successfully, retrieve the necessary agent data, and optionally export it. Blow are the key inputs.
Input Name | UI Type | Required | Description |
UCD_URL | TextBox | Yes | The full URL for the UCD website. |
UCD_Username | TextBox | Yes | Username to authenticate with UCD. |
UCD_Password | SecureBox | Yes | Password for the UCD account. |
Agent_Property_List | TextAreaBox | Yes | A newline-separated list of agent properties to be retrieved. |
Export_Data_Into_CSV | CheckBox | Optional | Select to export the agent details to a CSV file. |
File_Path | TextBox | Optional | File path or name for the CSV output. |
ACCEPT_SELF_SIGNED_CERTIFICATE | CheckBox | Optional | Accept self-signed certificates during connection. |
Updated plugin.xml
Below is the updated plugin.xml file, including the identified inputs, their types, and detailed descriptions. This configuration will make sure that the plugin asks for the input during its execution.
plugin.xml
<!-- The XML declaration <?xml version="1.0" encoding="UTF-8"?> specifies the version of XML being used and the character encoding for the document. --> <?xml version="1.0" encoding="UTF-8"?> <!-- Root element defining the IBM UCD plugin with its schema and namespace declarations --> <plugin xmlns="http://www.urbancode.com/PluginXMLSchema_v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- Plugin metadata including unique identifier, version, name, description, and tags --> <header> <identifier id="com.opensource" version="1" name="Agent Data Parser"/> <description>Plugin to get the list of agent and agent properties</description> <tag>Opensource/Custom/Utilities</tag> </header> <!-- Defines step in UCD process --> <step-type name="Get Agent Details List"> <description/> <!-- Defines plugin properties including UCD URL, credentials, agent properties, export options, and file path --> <properties> <property name="UCD_URL" required="true"> <property-ui type="textBox" label="UCD_URL" description="Enter the full URL for the UCD website. Here is an example: https://example.ucd.url:8443" default-value=""/> </property> <property name="UCD_Username" required="true"> <property-ui type="textBox" label="UCD Username" description="Enter Username to login into UCD" default-value=""/> </property> <property name="UCD_Password" required="true"> <property-ui type="secureBox" label="UCD Password" description="Enter Password to login into UCD" default-value=""/> </property> <property name="Agent_Property_List" required="true"> <property-ui type="textAreaBox" label="Agent Property List" description="List of properties sperated by new line" default-value=""/> </property> <property name="Export_Data_Into_CSV" required="true"> <property-ui type="checkBox" label="Export_Data_Into_CSV" description="When this checkbox is selected, a csv file will be created containing the agent's details" default-value="false"/> </property> <property name="ACCEPT_SELF_SIGNED_CERTIFICATE" required="true"> <property-ui type="checkBox" label="ACCEPT_SELF_SIGNED_CERTIFICATE" description="When this checkbox is checked, SELF SIGNED CERTIFICATE will be ACCEPTED" default-value="false"/> </property> <property name="File_Path" required="false"> <property-ui type="textBox" label="File_Path" description="File name in which data is to be added. For example, AgentData.csv" default-value=""/> </property> </properties> <!-- Post-processing script to set the status based on the exit code --> <post-processing> <![CDATA[ if (properties.get("exitCode") != 0) { properties.put("Status", "Failure"); } else { properties.put("Status", "Success"); } ]]> </post-processing> <!-- Command to execute the Java JAR file with input and output property files --> <command program="${JAVA_HOME}/bin/java"> <arg value="-jar"/> <arg file="IBM-DevOps-Deploy-Agent-Parser-1.0-jar-with-dependencies.jar"/> <arg file="${PLUGIN_INPUT_PROPS}"/> <arg file="${PLUGIN_OUTPUT_PROPS}"/> </command> </step-type> </plugin>
๐ Key Considerations When Modifying the plugin.xml File: 1. The XML declaration (<?xml version="1.0" encoding="UTF-8"?>) and the root <plugin> element with namespace attributes (xmlns and xmlns:xsi) must remain unchanged, as they define the XML version, file encoding, and namespace required for the UCD plugin. 2. Properties should be defined within the <properties> tag using the following format: <property name="<Property Name>" required="<true/false>"> <property-ui type="<Property Type>" label="<Property Label>" description="<Property Description>" default-value="<Default Value>"/> </property> ๐๐จ๐ฆ๐ฆ๐จ๐ง ๐๐ซ๐จ๐ฉ๐๐ซ๐ญ๐ฒ ๐๐ฒ๐ฉ๐๐ฌ ๐ข๐ง ๐ฉ๐ฅ๐ฎ๐ ๐ข๐ง.๐ฑ๐ฆ๐ฅ (๐๐๐๐ข๐ญ๐ข๐จ๐ง๐๐ฅ ๐ญ๐ฒ๐ฉ๐๐ฌ ๐๐ซ๐ ๐๐ฏ๐๐ข๐ฅ๐๐๐ฅ๐; ๐๐๐๐ฅ ๐๐ซ๐๐ ๐ญ๐จ ๐๐ฑ๐ฉ๐ฅ๐จ๐ซ๐): โณ textBox โณ checkBox โณ textAreaBox โณ secureBox
๐๐ญ๐๐ฉ ๐: ๐๐ฉ๐๐๐ญ๐ ๐ญ๐ก๐ ๐ข๐ง๐๐จ.๐ฑ๐ฆ๐ฅ ๐๐ง๐ ๐ฎ๐ฉ๐ ๐ซ๐๐๐.๐ฑ๐ฆ๐ฅ ๐๐ข๐ฅ๐๐ฌ ๐๐ฌ ๐ฉ๐๐ซ ๐ญ๐ก๐ ๐ซ๐๐ช๐ฎ๐ข๐ซ๐๐ฆ๐๐ง๐ญ๐ฌ:
info.xml
should contain metadata regarding the plugin, including version and descriptions, plus details about the versions it works with.upgrade.xml
contains modification logic if the plugin requires upgrading; modify to handle versioning and necessary transitions between plugin versions.๐กYou must ensure the usage of proper XML structure and preserve elements when changing any of these files.info.xml
<?xml version="1.0" encoding="UTF-8"?> <pluginInfo> <author name="Aniket Kakde"> <organization>example-org</organization> <email>example@gmail.com</email> <website>https://developer.ibm.com/urbancode/plugins/</website> <bio/> </author> <integration type="Automation"/> <tool-description>Agent Information parser for IBM UrbanCode Deploy</tool-description> <meta-html> <meta content="" name="description"/> <meta content="" name="keywords"/> </meta-html> <release-version>1</release-version> <release-notes> <release-note plugin-version="1"> Plugin version 1 </release-note> </release-notes> </pluginInfo>
upgrade.xml
<?xml version="1.0" encoding="UTF-8"?> <plugin-upgrade xmlns="http://www.urbancode.com/UpgradeXMLSchema_v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- This section can be used to define upgrade paths between plugin versions. For example: <version from="1" to="2"> <action name="Get Agent Details List" version="2"/> </version> For now, no upgrade changes are necessary. --> </plugin-upgrade>
๐๐ญ๐๐ฉ ๐: ๐๐ฆ๐ฉ๐ฅ๐๐ฆ๐๐ง๐ญ ๐ญ๐ก๐ ๐๐จ๐ ๐ข๐ ๐๐จ๐๐
In this step, we implement the primary logic of our plugin. The main method performs the following operations:
Determine the Working Directory:
- The application first retrieves and prints the current working directory, which helps with debugging and ensuring that file paths are resolved correctly.
Load Plugin Properties:
- The plugin reads the configuration properties from a file passed as the first argument (args[0]). These properties include critical information such as the UCD URL, credentials, agent property list, and export options.
Extract and Parse Inputs:
The required inputs are extracted from the properties file:
UCD_URL, UCD_Username, UCD_Password: For connecting to IBM UrbanCode Deploy.
Agent_Property_List: A newline-separated list of agent properties.
Export_Data_Into_CSV: A boolean flag to determine whether to create a CSV file.
File_Path: The name or path for the CSV output.
ACCEPT_SELF_SIGNED_CERTIFICATE: A flag indicating whether self-signed certificates are accepted.
Instantiate the Core Processing Object:
- With all required parameters collected and parsed, an instance of the GetAgentDetailsCustom class is created. This class encapsulates the logic to retrieve agent details and handle CSV export as needed.
Handle Exceptions and Resource Cleanup:
- The code uses a try-catch-finally block to ensure that any IO exceptions are caught and that the file input stream is properly closed, even if an error occurs.
Example Java Code
public static void main(String[] args) { // Retrieve and display the current working directory for debugging purposes String workingDir = System.getProperty("user.dir"); System.out.println("Working Directory: " + workingDir); // The properties file path is passed as the first argument String propsFilePath = args[0]; Properties prop = new Properties(); InputStream input = null; try { // Open and load the properties file input = new FileInputStream(propsFilePath); prop.load(input); // Extract the required properties from the file String UCDURL = prop.getProperty("UCD_URL"); String UCDUsername = prop.getProperty("UCD_Username"); String UCDPassword = prop.getProperty("UCD_Password"); String ListString = prop.getProperty("Agent_Property_List"); boolean CreateCSVFile = Boolean.parseBoolean(prop.getProperty("Export_Data_Into_CSV", "false")); String FileName = prop.getProperty("File_Path"); boolean acceptSelfSignedCertificate = Boolean.parseBoolean(prop.getProperty("ACCEPT_SELF_SIGNED_CERTIFICATE", "false")); // Instantiate the GetAgentDetailsCustom class with the parsed properties GetAgentDetailsCustom agentDetails = new GetAgentDetailsCustom( UCDUsername, UCDPassword, UCDURL, acceptSelfSignedCertificate, ListString, CreateCSVFile, FileName ); // Further processing with agentDetails would occur here (e.g., executing the agent retrieval logic) } catch (IOException ex) { // Handle any exceptions that occur during file access or property loading ex.printStackTrace(); System.exit(1); } finally { // Ensure the input stream is closed to prevent resource leaks if (input != null) { try { input.close(); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } } }
๐๐ญ๐๐ฉ ๐: ๐๐ฉ๐๐๐ญ๐ ๐ฉ๐จ๐ฆ.๐ฑ๐ฆ๐ฅ
Ensure that the pom.xml file is updated to reflect the required dependencies, plugin configurations, and any necessary versioning. This step is crucial to ensure that your plugin integrates smoothly with the build process and resolves the necessary libraries.
๐ฃ The section in pom.xml defines how the project shall be compiled and packaged. It has the source code located within the src directory. The compiler is configured in maven-compiler-plugin that compiles source and target codes using Java 11. Packaging of the project into a JAR file by including all of its dependencies, maven-assembly-plugin has been used for this purpose. The manifest defines the main class as com.opensource.GetAgentDetailsCustom, and the jar-with-dependencies descriptor is used to include all libraries into the JAR. This sets up compilation and packaging of the project into a distributable, dependency-bundled JAR.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>IBM-DevOps-Deploy-Agent-Parser</artifactId> <version>1.0</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>11</source> <target>11</target> </configuration> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>com.opensource.GetAgentDetailsCustom</mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build> <dependencies> <!-- https://mvnrepository.com/artifact/org.json/json --> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20230618</version> </dependency> </dependencies> </project>
๐๐ญ๐๐ฉ ๐: ๐๐ฎ๐ข๐ฅ๐ ๐ญ๐ก๐ ๐๐ซ๐จ๐ฃ๐๐๐ญ
To build the project, use the following Maven command:
mvn clean compile assembly:single
This command will clean any previously compiled files, compile the source code, and package the project into a JAR file. The resulting JAR file will be located in the target directory.
๐๐ญ๐๐ฉ ๐: ๐๐๐๐ค๐๐ ๐ ๐
๐ข๐ฅ๐๐ฌ ๐ญ๐จ ๐๐ฎ๐ข๐ฅ๐ ๐ญ๐ก๐ ๐๐ฅ๐ฎ๐ ๐ข๐ง
After building the JAR file in Step 5, follow these steps to package your plugin:
Copy the JAR file generated in the target directory and place it in the same directory where your plugin.xml, upgrade.xml, and info.xml files are located.
Compress all the files (JAR file, plugin.xml, upgrade.xml, and info.xml) into a.zip archive.
This will result in a ZIP file containing all the components for the plugin to be deployed.
๐๐ญ๐๐ฉ ๐: ๐๐ฉ๐ฅ๐จ๐๐ ๐๐ฅ๐ฎ๐ ๐ข๐ง ๐ข๐ง๐ญ๐จ ๐๐๐.
Once the ZIP file containing the JAR, plugin.xml, upgrade.xml, and info.xml is ready, follow these steps to upload it into IBM UrbanCode Deploy (UCD):
Log in to the UCD instance.
Navigate to "Settings" in the UCD dashboard.
Click on "Automation Plugins" option.
Click on "Load Plugin" option.
Select the ZIP file you created in Step 6 and upload it.
After uploading, UCD will process the plugin, and you should see it listed in the available plugins.
RoadMap
Sample Output
Advantages Over Manual Processes
No Resource Dependency:
Automation reduces the need for manual intervention.Reduced Human Error:
Minimizes mistakes common in manual data handling.98% Time Savings:
Fetches 6000 agents in 1 hour 40 minutes versus 300 hours manually.
Useful Resource
๐ License
IBM DevOps Deploy (IBM UrbanCode Deploy) Custom Plugin Development ยฉ 2025 by Aniket Kakde is licensed under [CC BY 4.0](creativecommons.org/licenses/by/4.0). You are free to share and adapt this content with proper attribution.