Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ RUN sudo dnf install -y oraclelinux-release-el9 && \
sudo chown -R $USERNAME:$USERNAME /cd3user/ && \
sudo sed -i -e 's/\r$//' /cd3user/oci_tools/cd3_automation_toolkit/shell_script.sh && \
bash /cd3user/oci_tools/cd3_automation_toolkit/shell_script.sh && \
sudo microdnf install git-2.39.3 -y && \
sudo dnf clean all && \
sudo rm -rf /var/cache/dnf && \
sudo chmod -R 740 /cd3user/ && \
Expand All @@ -67,8 +68,8 @@ sudo rm -rf terraform-provider-null_${TF_NULL_PROVIDER}_linux_amd64.zip terrafor
fi

##################################### START INSTALLING JENKINS ###################################
ARG JENKINS_VERSION=2.504.1
ARG JENKINS_SHA=81026db18b0c4aad6b62cf408e4c42e5797661b41c517b37df606238e89b9df1
ARG JENKINS_VERSION=2.504.3
ARG JENKINS_SHA=ea8883431b8b5ef6b68fe0e5817c93dc0a11def380054e7de3136486796efeb0
ARG JENKINS_PLUGIN_MANAGER_VERSION=2.12.13
ARG PLUGIN_CLI_URL=https://github.com/jenkinsci/plugin-installation-manager-tool/releases/download/${JENKINS_PLUGIN_MANAGER_VERSION}/jenkins-plugin-manager-${JENKINS_PLUGIN_MANAGER_VERSION}.jar

Expand All @@ -95,7 +96,6 @@ COPY --chown=cd3user:cd3user jenkins_install/plugins.txt ${REF}/plugins.txt
RUN if [ "$USE_DEVOPS" == "YES" ]; then \
sudo microdnf install -y java-21-openjdk && \
sudo microdnf install -y java-21-openjdk-devel && \
sudo microdnf install git-2.39.3 -y && \
sudo mkdir -p ${REF}/init.groovy.d && \
sudo chown -R cd3user:cd3user ${JENKINS_INSTALL} && \
sudo curl -fsSL http://updates.jenkins-ci.org/download/war/${JENKINS_VERSION}/jenkins.war -o ${JENKINS_INSTALL}/jenkins.war && \
Expand Down
5 changes: 3 additions & 2 deletions OCIWorkVMStack/oci_images.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
variable "marketplace_source_images" {
type = map(object({
/*type = map(object({
ocid = string
is_pricing_associated = bool
compatible_shapes = set(string)
Expand All @@ -10,5 +10,6 @@ variable "marketplace_source_images" {
is_pricing_associated = false
compatible_shapes = []
}
}
}*/
default = ""
}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<br>

[What's New](https://github.com/oracle-devrel/cd3-automation-toolkit/releases/tag/v2026.1.2) &nbsp;•&nbsp;[Excel Templates](https://oracle-devrel.github.io/cd3-automation-toolkit/latest/excel-templates/) &nbsp;•&nbsp;[CD3 Docs](https://oracle-devrel.github.io/cd3-automation-toolkit/latest/cd3-overview/)&nbsp;•&nbsp; [Watch & Learn](https://www.youtube.com/playlist?list=PLPIzp-E1msrbJ3WawXVhzimQnLw5iafcp) &nbsp;•&nbsp;[Blogs & Tutorials](https://oracle-devrel.github.io/cd3-automation-toolkit/latest/tutorials/) &nbsp;•&nbsp;[Livelabs](https://apexapps.oracle.com/pls/apex/f?p=133:180:112501098061930::::wid:3724) &nbsp;•&nbsp;[Slack Channel](https://oracle-devrel.github.io/cd3-automation-toolkit/latest/queries)
[What's New](https://github.com/oracle-devrel/cd3-automation-toolkit/releases/tag/v2026.2.0) &nbsp;•&nbsp;[Excel Templates](https://oracle-devrel.github.io/cd3-automation-toolkit/latest/excel-templates/) &nbsp;•&nbsp;[CD3 Docs](https://oracle-devrel.github.io/cd3-automation-toolkit/latest/cd3-overview/)&nbsp;•&nbsp; [Watch & Learn](https://www.youtube.com/playlist?list=PLPIzp-E1msrbJ3WawXVhzimQnLw5iafcp) &nbsp;•&nbsp;[Blogs & Tutorials](https://oracle-devrel.github.io/cd3-automation-toolkit/latest/tutorials/) &nbsp;•&nbsp;[Livelabs](https://apexapps.oracle.com/pls/f?p=133:180:112501098061930::::wid:3724) &nbsp;•&nbsp;[Slack Channel](https://oracle-devrel.github.io/cd3-automation-toolkit/latest/queries)

<br>

Expand Down Expand Up @@ -74,7 +74,7 @@ Evaluate Terraform plans to identify potential security risks, misconfigurations
</table>


📌 The Toolkit also extends its support to <b>ADB@Azure</b>
📌 The Toolkit now support to <b>ADB@Azure</b>, <b>Exa@Azure(create only)</b>, <b>ADB@GCP</b>, <b>Exa@GCP(create only)</b>.

<br>

Expand Down
14 changes: 13 additions & 1 deletion cd3_automation_toolkit/Release-Notes
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
-------------------------------------
CD3 Automation Toolkit Tag v2026.2.0
Jul 31st, 2026
-------------------------------------
1. Added multi-cloud Database Service support for Azure and GCP, including creation of ADB and Exadata resources, ADB export, and offline tfvars generation. Exadata export is not included in this release.
2. Added support for multiple secondary VNICs for OCI instances.
3. Added support for preemptible node pool configuration for OKE.
4. Updated the CIS compliance report to version 3.2.1.
5. Added identity output separation and fixed RPC deduplication and user export behavior.
6. Included bug fixes for ADB, NSG rules, buckets, the OCI Resource Manager stack, and other minor issues.
7. Upgraded Jenkins core from 2.504.1 to 2.504.3 for compatibility with the current Jenkins plugin update-center catalog.

-------------------------------------
CD3 Automation Toolkit Tag v2026.1.2
Jul 10th, 2026
Expand All @@ -9,7 +21,7 @@ CD3 Automation Toolkit Tag v2026.1.1
May 8th, 2026
-------------------------------------
1. Support for export of resources from all child compartments of a parent without specifying them separately in command line.
2. Deprecate python script createTenancyConfig.py. Instead use connectCloud.py
2. Deprecate python scripts createTenancyConfig.py and setUpOCI.py. Instead use connectCloud.py and setUpCloud.py
3. Fixed ordering issue for views for export of DNS resolvers.
4. Minor internal bug fixes.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@ def normalize_enum_token(value):
return s.split(".", 1)[1] if "." in s else s


def _format_rg_vnet_subnet_from_id(net_id: str) -> str:
"""Return 'resourceGroup@vnet::subnet' from a subnet ARM ID."""
def _parse_subnet_arm_id(net_id: str):
"""Return the resource group, virtual network, and subnet from a subnet ARM ID."""
if not net_id:
return ""
return "", "", ""
parts = net_id.strip("/").split("/")
try:
rg = parts[parts.index("resourceGroups") + 1]
vnet = parts[parts.index("virtualNetworks") + 1]
subnet = parts[parts.index("subnets") + 1]
return f"{rg}@{vnet}::{subnet}"
return rg, vnet, subnet
except (ValueError, IndexError):
return ""
return "", "", ""


def _get_rg_from_id(resource_id: str) -> str:
Expand Down Expand Up @@ -106,21 +106,13 @@ def print_adbs_azure(adb, values_for_column: Dict[str, List], state: Dict, tf_or
# Tags (dict) — kept as metadata only if the sheet has 'Common Tags' column(not used yet)
common_tags = azrCommonTools._flatten_tags(getattr(adb, "tags", None))

# Prefer subnetId to derive rg@vnet::subnet; private endpoint IDs don't contain vnet/subnet names
# Prefer subnetId because private endpoint IDs don't contain vnet/subnet names
subnet_id = pick_first_not_none(
getattr(props, "subnet_id", None),
getattr(props, "subnetId", None),
)
formatted_net = _format_rg_vnet_subnet_from_id(subnet_id)

# Optional: keep raw IDs if needed elsewhere
network_details_raw = pick_first_not_none(
getattr(props, "subnet_id", None),
getattr(props, "subnetId", None),
getattr(props, "private_endpoint_id", None),
getattr(props, "privateEndpointId", None),
"",
)
network_rg, vnet_name, subnet_name = _parse_subnet_arm_id(subnet_id)
odb_network_details = f"{network_rg}::{vnet_name}" if network_rg and vnet_name else ""

# Whitelisted IPs (array of strings)
ips_list = pick_first_not_none(
Expand Down Expand Up @@ -204,9 +196,11 @@ def print_adbs_azure(adb, values_for_column: Dict[str, List], state: Dict, tf_or
values_for_column[col_header].append(adb_location)
elif col_header == "ADB Display Name":
values_for_column[col_header].append(adb_name)
elif col_header == "Network Details":
# Write the formatted rg@vnet::subnet if available; else leave blank or fall back to raw
values_for_column[col_header].append(formatted_net or "")
# Keep network and subnet separate because the ADB-Azure generator reads them from two workbook columns.
elif col_header == "ODB Network Details":
values_for_column[col_header].append(odb_network_details)
elif col_header == "ODB Network Subnet Details":
values_for_column[col_header].append(subnet_name)
elif col_header == "Whitelisted IP Addresses":
values_for_column[col_header].append(whitelisted_ips)
elif col_header == "DB Name":
Expand Down Expand Up @@ -341,4 +335,4 @@ def export_adb_azure(inputfile: str, outdir: str,credentials,
if importCommands.get("global"):
importCommands["global"] += f'\n{tf_or_tofu} plan\n'
with open(script_file, 'a', encoding='utf-8') as importCommandsfile:
importCommandsfile.write(init_commands + importCommands["global"])
importCommandsfile.write(init_commands + importCommands["global"])
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ enforce_container_engine_config {

container.is_private_cluster
container.is_encryption_enabled
container.is_pod_security_policy_enabled
}

#To enforce secure configuration for container instances
Expand Down
6 changes: 5 additions & 1 deletion cd3_automation_toolkit/common/python/commonTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ def write_to_cd3(values_for_column, cd3file, sheet_name,append=False):


#rows_len=len(rows)
rows_len = len(values_for_column["Region"])
try:
rows_len = len(values_for_column["Region"])
except KeyError as e:
rows_len = len(values_for_column["Location"])

sheet_max_rows = sheet.max_row
#If no rows exported from OCI, remove the sample data as well
if(rows_len == 0) :
Expand Down
2 changes: 1 addition & 1 deletion cd3_automation_toolkit/connectGCP.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
prefix=

# Auth Mechanism for GCP APIs - api_key
# Please make sure to add IAM policies for service account before executing connectContainerToGCP.py
# Please make sure to add IAM policies for service account before executing connectCloud.py
auth_mechanism=api_key
# Path to JSON file having private key information for the service account;
# Defaults to /cd3user/gcp/keys/gcp_api_private.json when left empty
Expand Down
Binary file modified cd3_automation_toolkit/example/CD3-Azure-template.xlsx
Binary file not shown.
Binary file modified cd3_automation_toolkit/example/CD3-Blank-template.xlsx
Binary file not shown.
Binary file not shown.
Binary file modified cd3_automation_toolkit/example/CD3-CIS-template.xlsx
Binary file not shown.
Binary file modified cd3_automation_toolkit/example/CD3-Firewall-template.xlsx
Binary file not shown.
Binary file modified cd3_automation_toolkit/example/CD3-GCP-template.xlsx
Binary file not shown.
Binary file modified cd3_automation_toolkit/example/CD3-HubSpoke-template.xlsx
Binary file not shown.
Binary file modified cd3_automation_toolkit/example/CD3-SingleVCN-template.xlsx
Binary file not shown.
3 changes: 3 additions & 0 deletions cd3_automation_toolkit/gcpcloud/python/database/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@

from .create_terraform_exa_infra_gcp import create_terraform_exa_infra_gcp
from .create_terraform_exa_vmclusters_gcp import create_terraform_exa_vmclusters_gcp
from .create_terraform_adb_gcp import create_terraform_adb_gcp
from .export_adb_gcp import export_adb_gcp
from .export_exa_infra_gcp import export_exa_infra_gcp

Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#!/usr/bin/python3
# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
#
# This script will produce a Terraform file that will be used to set up OCI Database
# Autonomous Database @GCP
#
# Author: Suruchi
# Oracle Consulting
#
import os
import sys
import re
from jinja2 import Environment, FileSystemLoader
from pathlib import Path
sys.path.append(os.getcwd()+"/..")
from common.python.commonTools import *
import gcpcloud.python.gcpCommonTools as gcpCommonTools


######
# Required Inputs- CD3 excel file, prefix AND outdir
######
# Execution of the code begins here
def create_terraform_adb_gcp(inputfile, outdir, prefix):

filename = inputfile
sheetName = "ADB-GCP"
resource=sheetName.lower()
auto_tfvars_filename = prefix + '_' + sheetName.lower() + '.auto.tfvars'

# Load the template file
file_loader = FileSystemLoader(f'{Path(__file__).parent}/templates')
env = Environment(loader=file_loader, keep_trailing_newline=True, trim_blocks=True, lstrip_blocks=True)
template = env.get_template('adb-gcp-template')

tfStr=''


# Read cd3 using pandas dataframe
df, col_headers = commonTools.read_cd3(filename, sheetName)
#Remove empty rows
df = df.dropna(how='all')
df = df.reset_index(drop=True)

# List of the column headers
dfcolumns = df.columns.values.tolist()

# Iterate over rows
for i in df.index:
location = str(df.loc[i, 'Location']).strip()
# Encountered <End>
if (location in commonTools.endNames):
break

location=location.strip().lower()

# temporary dictionary1 and dictionary2
tempStr = {}
tempdict = {}

# All columns are mandatory except customer contacts and tags
if (str(df.loc[i, 'Location']).lower() == 'nan' or \
str(df.loc[i, 'Project']).lower() == 'nan' or \
str(df.loc[i, 'ADB Display Name']).lower() == 'nan' or \
#str(df.loc[i, 'ODB Network Details']).lower() == 'nan' or \
#str(df.loc[i, 'ODB Network Subnet Details']).lower() == 'nan' or \
str(df.loc[i, 'DB Version']).lower() == 'nan'):
print("\nAll fields are mandatory. Please enter a value and try again !!")
print("\n** Exiting **")
exit(1)


for columnname in dfcolumns:
# Column value
columnvalue = str(df[columnname][i]).strip()

# Check for boolean/null in column values
columnvalue = commonTools.check_columnvalue(columnvalue)

# Check for multivalued columns
tempdict = commonTools.check_multivalues_columnvalue(columnvalue,columnname,tempdict)


# Process Defined and Freeform Tags
if columnname.lower() in gcpCommonTools.tagColumns:
tempdict = gcpCommonTools.split_tag_values(columnname, columnvalue, tempdict)

if columnname == "ADB Display Name":
display_name = columnvalue.strip()
display_tf_name = commonTools.check_tf_variable(display_name)
autonomous_database_id = re.sub(r'[^a-z0-9-]', '', display_name.lower())
tempdict = {'display_name': display_name, 'display_tf_name': display_tf_name,
'autonomous_database_id': autonomous_database_id}
if columnname == "Autonomous Database ID":
columnvalue=columnvalue.strip()
if columnvalue!="":
tempdict = {'autonomous_database_id': columnvalue}


if columnname == 'Database Workload':
autonomous_value = columnvalue.strip().lower()
tempdict = {'db_workload': autonomous_value}

if columnname == "ODB Network Details":
if columnvalue!="":
values = columnvalue.split("::")
if len(values) < 3:
print("Invalid Value for ODB Network Details. Exiting!!")
exit(1)

if values[0].strip().upper() == "CREATE":
if len(values) != 5:
print("Invalid Value for ODB Network Details. Exiting!!")
exit(1)
create_odb_network = "true"
odb_network_project = values[1].strip()
vpc_network_name = values[2].strip()
odb_network_id = values[3].strip()
odb_network_gcp_oracle_zone = values[4].strip()

else:
create_odb_network = "false"
odb_network_project = values[0].strip()
vpc_network_name = values[1].strip()
odb_network_id = values[2].strip()
if (len(values) == 4):
odb_network_gcp_oracle_zone = values[3].strip()
else:
odb_network_gcp_oracle_zone = ""

tempdict = {'create_odb_network': create_odb_network, 'odb_network_project': odb_network_project,
'vpc_network_name': vpc_network_name, 'odb_network_id': odb_network_id,
'odb_network_gcp_oracle_zone': odb_network_gcp_oracle_zone}

if columnname == "ODB Network Subnet Details":
if columnvalue != "":
values = columnvalue.split("::")
if len(values) < 1:
print("Invalid Value for ODB Network Subnets Details. Exiting!!")
exit(1)

if values[0].strip().upper() == "CREATE":
if len(values) != 3:
print("Invalid Value for ODB Network Subnets Details. Exiting!!")
exit(1)
create_odb_network_subnets = "true"
odb_client_subnet_id = values[1].strip()
client_subnet_cidr = values[2].strip()


else:
create_odb_network_subnets = "false"
odb_client_subnet_id = values[0].strip()
client_subnet_cidr = ""


tempdict = {'create_odb_network_subnets': create_odb_network_subnets,
'odb_client_subnet_id': odb_client_subnet_id, 'client_subnet_cidr': client_subnet_cidr}


columnname = commonTools.check_column_headers(columnname)
tempStr[columnname] = str(columnvalue).strip()
tempStr.update(tempdict)

# Write all info to TF string
tfStr=tfStr + template.render(tempStr)


if(tfStr!=''):
outfile = outdir + "/" + auto_tfvars_filename
commonTools.backup_file(outdir, resource, auto_tfvars_filename)
src = "##Add New ADB @GCP here##"
tfStr= template.render(count=0).replace(src, tfStr + "\n" + src)
tfStr = "".join([s for s in tfStr.strip().splitlines(True) if s.strip("\r\n").strip()])
oname=open(outfile,'w')
oname.write(tfStr)
oname.close()
print(outfile + " containing TF for ADB @GCP has been created")
Loading