{"id":1555,"date":"2025-04-29T19:46:15","date_gmt":"2025-04-29T19:46:15","guid":{"rendered":"https:\/\/adrianotanaka.com.br\/?p=1555"},"modified":"2025-04-29T19:46:15","modified_gmt":"2025-04-29T19:46:15","slug":"terraform-rest-api-and-oci-devops-to-deploy-and-manage-oci-goldengate","status":"publish","type":"post","link":"https:\/\/adrianotanaka.com.br\/index.php\/2025\/04\/29\/terraform-rest-api-and-oci-devops-to-deploy-and-manage-oci-goldengate\/","title":{"rendered":"Terraform, REST API and OCI DevOps to deploy and manage OCI GoldenGate"},"content":{"rendered":"\n<p>These days, automation is a no-brainer when working with cloud environments. Following best practices can really speed things up and get your product to market faster. In this post, I\u2019ll show you how to use Terraform, REST API, and OCI DevOps to build a CI\/CD pipeline. I\u2019ll cover the basics of each tool, so you\u2019ll have a solid starting point. Got questions? Drop them in the comments\u2014I\u2019m here to help!<\/p>\n\n\n\n<p>Terraform is a powerful tool for deploying infrastructure as code, and I\u2019ve relied on it for a long time to automate and manage my infrastructure efficiently. One key thing to understand is that Oracle provides a Terraform provider\u2014a piece of code that allows Terraform to integrate with Oracle&#8217;s services. Additionally, there are specific resources to support OCI GoldenGate, which translates Terraform configurations into OCI resources.<\/p>\n\n\n\n<p>One important best practice is to store your variables in a dedicated file to avoid hardcoding values in your code. This approach keeps your configurations clean and flexible. Here\u2019s an example of my tf.vars file (and don\u2019t forget to load it before running your code!):<\/p>\n\n\n\n<div class=\"wp-block-group is-layout-constrained wp-block-group-is-layout-constrained\">\n<pre class=\"wp-block-code\"><code>export TF_VAR_region=YOUR_REGION\nexport TF_VAR_tenancy_ocid=YOUR_TENANCY_OCID\nexport TF_VAR_user_ocid=YOUR_USER_OCID\nexport TF_VAR_private_key_path=YOUR_PEM_FILE\nexport TF_VAR_fingerprint=XXXXX\nexport TF_VAR_compartment_ocid=YOUR_COMPARTMENT_OCID<\/code><\/pre>\n<\/div>\n\n\n\n<p>And my provider.tf file (the file that tells terraform that we are working with OCI):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>provider \"oci\" {\n&nbsp; region = var.region\n}\n\nvariable \"tenancy_ocid\" {}\nvariable \"region\" {}\nvariable \"compartment_ocid\" {}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>OCI GoldenGate Terraform Resources<\/strong><\/h2>\n\n\n\n<p>Using Terraform is like building with Lego\u2014you need all the pieces in place to make it work. In this case, our building blocks are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>oci_golden_gate_deployment<\/strong> This resource is used to create deployments, which include components like the subnet and OCPU quantity. It also manages the lifecycle of your deployment, including starting, stopping, and scaling.<\/li>\n\n\n\n<li><strong>oci_golden_gate_connection<\/strong> This resource handles connections for your GoldenGate deployment.<\/li>\n\n\n\n<li><strong>oci_golden_gate_connection_assignment<\/strong> This resource assigns connections to your deployment. Connections can be shared across multiple deployments, allowing you to reuse the same object efficiently.<\/li>\n<\/ul>\n\n\n\n<p><strong>Deployment Resource (oci_golden_gate_deployment)<\/strong><\/p>\n\n\n\n<p>When working with Terraform files, I prefer to describe resource parameters using a list object. This approach makes the code more reusable and easier to manage. Here&#8217;s how I structure the required information for deployment:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>variable \"deployment_list\" {\n\u00a0 type = list(object({\n\u00a0\u00a0\u00a0 deployment_name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 deployment_subnet\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 deployment_type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 deployment_ocpu\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = number\n\u00a0\u00a0\u00a0 deployment_autoscaling = bool\n\u00a0\u00a0\u00a0 #deployment_compartment = string\n\u00a0\u00a0\u00a0 deployment_description\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 deployment_tech\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 deployment_user\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 deployment_password_secret_id = string\n\u00a0\u00a0\u00a0 deployment_status\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0 }))\n\u00a0 default = &#91;{ deployment_name = \"ORCL\",\n\u00a0\u00a0\u00a0 deployment_subnet\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"ocid1.subnet.oc1.xxxxxxx\",\n\u00a0\u00a0\u00a0 deployment_type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"DEVELOPMENT_OR_TESTING\",\n\u00a0\u00a0\u00a0 deployment_tech\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"DATABASE_ORACLE\",\n\u00a0\u00a0\u00a0 deployment_ocpu\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = 2,\n\u00a0\u00a0\u00a0 deployment_autoscaling\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = true,\n\u00a0\u00a0\u00a0 deployment_description\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"abc123\",\n\u00a0\u00a0\u00a0 deployment_user\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"oggadmin\",\n\u00a0\u00a0\u00a0 deployment_password_secret_id = \"ocid1.vaultsecret.oc1.xxxxxx\",\n\u00a0\u00a0\u00a0 deployment_status = \"ACTIVE\" },\n\u00a0\u00a0\u00a0 { deployment_name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"BIGDATA\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 deployment_subnet\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"ocid1.subnet.oc1.xxxxxx\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 deployment_type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"DEVELOPMENT_OR_TESTING\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 deployment_tech\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"BIGDATA\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 deployment_ocpu\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = 2,\n\u00a0\u00a0\u00a0\u00a0\u00a0 deployment_autoscaling\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = true,\n\u00a0\u00a0\u00a0\u00a0\u00a0 deployment_description\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"abc123\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 deployment_user\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"oggadmin\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 deployment_password_secret_id = \"ocid1.vaultsecret.oc1.xxxxxxxxx\",\n\u00a0\u00a0\u00a0 deployment_status = \"ACTIVE\" }\n\u00a0 ]\n}<\/code><\/pre>\n\n\n\n<p>And I create a loop over that variable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resource \"oci_golden_gate_deployment\" \"ogg_deployments\" {\n\u00a0 #Required\n\u00a0 for_each = { for d in var.deployment_list : d.deployment_name => d }\n\u00a0 compartment_id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = var.compartment_ocid #var.compartment_id\n\u00a0 cpu_core_count\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.deployment_ocpu\n\u00a0 deployment_type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.deployment_tech #PRODUCTION,DEVELOPMENT_OR_TESTING\n\u00a0 display_name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = each.key\n\u00a0 is_auto_scaling_enabled = each.value.deployment_autoscaling\n\u00a0 license_model\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"BRING_YOUR_OWN_LICENSE\" #BYOL=BRING_YOUR_OWN_LICENSE INCLUDE=LICENSE_INCLUDED\n\u00a0 subnet_id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.deployment_subnet\n\u00a0 description\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.deployment_description\n\u00a0 environment_type = each.value.deployment_type\n\u00a0 is_public\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = false\n\u00a0 ogg_data {\n\u00a0\u00a0\u00a0 #Required\n\u00a0\u00a0\u00a0 deployment_name = each.value.deployment_name\n\u00a0\u00a0\u00a0 #Optional\n\u00a0\u00a0\u00a0 #admin_password\u00a0\u00a0 = each.value.deployment_password\n\u00a0\u00a0\u00a0 admin_username = each.value.deployment_user\n\u00a0\u00a0\u00a0 #ogg_version\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0= var.deployment_ogg_data_ogg_version\n\u00a0\u00a0\u00a0 password_secret_id = each.value.deployment_password_secret_id\n\u00a0 }\n\u00a0 state = each.value.deployment_status\n}<\/code><\/pre>\n\n\n\n<p><strong>oci_golden_gate_connection (deploymentConnection.tf)<\/strong><\/p>\n\n\n\n<p>Although the resources are independent, for this code to work, you must first create the deployments\u2014or run everything together. This is because some details are retrieved from the deployment.<br>Below is the familiar resource object:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>variable \"connection_list\" {\n\u00a0 type = list(object({\n\u00a0\u00a0\u00a0 connection_name\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 connection_subnet = string\n\u00a0\u00a0\u00a0 technology_type\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 routing_method\u00a0\u00a0\u00a0 = string\n\u00a0 }))\n\u00a0 default = &#91;{ connection_name = \"orcl\", connection_subnet = \"ocid1.subnet.oc1.uk-london-1.xxxxxxx\", technology_type = \"GOLDENGATE\", routing_method = \"DEDICATED_ENDPOINT\" }]\n}\nresource \"oci_golden_gate_connection\" \"ogg_deployment_connection\" {\n\u00a0 for_each = { for d in oci_golden_gate_deployment.ogg_deployments : d.display_name => d }\n\u00a0 #Required\n\u00a0 compartment_id\u00a0 = var.compartment_ocid\n\u00a0 connection_type = \"GOLDENGATE\"\n\u00a0 display_name\u00a0\u00a0\u00a0 = \"conn_${each.key}\"\n\u00a0 technology_type = \"GOLDENGATE\"\n\u00a0 description = \"ttt\"\n\u00a0 host\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.fqdn\n\u00a0 private_ip\u00a0\u00a0\u00a0\u00a0 = each.value.private_ip_address\n\u00a0 port\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = 443\n\u00a0 subnet_id\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.subnet_id\n\u00a0 routing_method = \"DEDICATED_ENDPOINT\"\n\u00a0 trigger_refresh = true\n}<\/code><\/pre>\n\n\n\n<p>The key element here is the <strong>for_each<\/strong> loop, which iterates through each created deployment to create a connection for it. It&#8217;s crucial that both the <code>connection_type<\/code> and <code>technology_type<\/code> are set to <strong>GOLDENGATE<\/strong> for proper functionality.<\/p>\n\n\n\n<p><strong>oci_golden_gate_connection(createConnection.tf)<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u00a0variable \"connection_list_targets\" {\n\u00a0 type = list(object({\n\u00a0\u00a0\u00a0 connection_name\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 connection_subnet = string\n\u00a0\u00a0\u00a0 technology_type\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 routing_method\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 target_ip\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 fqdn\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = string\n\u00a0\u00a0\u00a0 target_port\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = number\n\u00a0\u00a0\u00a0 connection_type\u00a0\u00a0 = string\n\u00a0 }))\n\u00a0 default = &#91;{ connection_name = \"orcl_src\", connection_subnet = \"ocid1.subnet.oc1.uk-london-1.xxxxx\", connection_type = \"ORACLE\", technology_type = \"ORACLE_DATABASE\", routing_method = \"DEDICATED_ENDPOINT\", target_ip = \"172.19.1.95\", fqdn = \"meudb.com.br\", target_port = 1521 }]\n}\nresource \"oci_golden_gate_connection\" \"ogg_connection\" {\n\u00a0 for_each\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = { for d in var.connection_list_targets : d.connection_name => d }\n\u00a0 compartment_id\u00a0\u00a0\u00a0 = var.compartment_ocid\n\u00a0 connection_type\u00a0\u00a0 = each.value.connection_type\n\u00a0 display_name\u00a0\u00a0\u00a0\u00a0\u00a0 = \"conn_${each.key}\"\n\u00a0 technology_type\u00a0\u00a0 = each.value.technology_type\n\u00a0 username\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"system\"\n\u00a0 password\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = \"XXXXXX\"\n\u00a0 connection_string = \"${each.value.fqdn}:${each.value.target_port}\"\n\u00a0 description\u00a0\u00a0\u00a0 = \"ttt\"\n\u00a0 host\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.fqdn\n\u00a0 private_ip\u00a0\u00a0\u00a0\u00a0 = each.value.target_ip\n\u00a0 port\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.target_port\n\u00a0 subnet_id\u00a0\u00a0\u00a0\u00a0\u00a0 = each.value.connection_subnet\n\u00a0 routing_method = \"DEDICATED_ENDPOINT\"\n\u00a0 trigger_refresh = true\n}<\/code><\/pre>\n\n\n\n<p>This script will create a connection to a Oracle Database (connection_type=\u201dORACLE\u201d) using a dedicated endpoint(routing_method=\u201dDEDICATED_ENDPOINT), see that we are using an object to hold the information and its easy to update\/adjust according to your requirements.<\/p>\n\n\n\n<p><strong>Connection Assignement (assignConnection.tf)<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>variable \"assign_conn\" {\n  type = list(object({\n    connection_id     = string\n    deployment_target = string\n\n\n  }))\n\n  default = &#91;{ connection_id = \"ocid1.goldengateconnection.oc1.uk-london-1.xxxxx\",\n    deployment_target = \"ocid1.goldengatedeployment.oc1.uk-london-1.xxxxx\" },\n    { connection_id = \"ocid1.goldengateconnection.oc1.uk-london-1.xxx\",\n    deployment_target = \"ocid1.goldengatedeployment.oc1.uk-london-1.xxx\" }\n  ]\n}\n\n\n\nresource \"oci_golden_gate_connection_assignment\" \"connection_assignment\" {\n  for_each = { for c in var.assign_conn : c.connection_id => c }\n  #Required\n\n  connection_id = each.value.connection_id\n  deployment_id = each.value.deployment_target\n}<\/code><\/pre>\n\n\n\n<p>This code will assign a connection(connection_id) to a deployment(deployment_target).<\/p>\n\n\n\n<p>Now that our infrastructure is (hopefully) deployed and running, we can move on to deploying and managing GoldenGate processes.<\/p>\n\n\n\n<p>To get a better grasp of how this works, I recommend checking out the official documentation: <a href=\"https:\/\/docs.oracle.com\/en\/middleware\/goldengate\/core\/23\/oggra\/index.html\">https:\/\/docs.oracle.com\/en\/middleware\/goldengate\/core\/23\/oggra\/index.html<\/a><\/p>\n\n\n\n<p>There, you\u2019ll find essential information such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>How to authenticate with the GoldenGate API<\/li>\n\n\n\n<li>Endpoints for various operations<\/li>\n\n\n\n<li>Operations and examples for each GoldenGate endpoint\/process<\/li>\n<\/ul>\n\n\n\n<p><strong>Important Note:<\/strong> For OCI GoldenGate, be sure to append <code>\/adminsrvr<\/code> to some endpoints.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>GoldenGate<\/td><td>OCI GoldenGate<\/td><\/tr><tr><td>\/services\/v2\/logs<\/td><td>\/services\/adminsrvr\/v2\/logs<\/td><\/tr><tr><td>\/services\/v2\/installation\/services<\/td><td>\/services\/adminsrvr\/v2\/installation\/services<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>When it comes to authenticating with OCI GoldenGate, you have a few options. In this example, I\u2019ll use a username and password for simplicity, but tokens are also a viable alternative.<\/p>\n\n\n\n<p>You can run a curl command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;tanaka@ ~]$ curl -k -u USER:PASSWORD -X GET https:\/\/SERVICE_ENDPOINT\/services\/adminsrvr\/v2\/logs | jq -r\n\u00a0 % Total\u00a0\u00a0\u00a0 % Received % Xferd\u00a0 Average Speed\u00a0\u00a0 Time\u00a0\u00a0 \u00a0Time\u00a0\u00a0\u00a0\u00a0 Time\u00a0 Current\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Dload\u00a0 Upload\u00a0\u00a0 Total\u00a0\u00a0 Spent\u00a0\u00a0\u00a0 Left\u00a0 Speed\n100\u00a0 2250\u00a0 100\u00a0 2250\u00a0\u00a0\u00a0 0\u00a0\u00a0\u00a0\u00a0 0\u00a0\u00a0 2416\u00a0\u00a0\u00a0\u00a0\u00a0 0 --:--:-- --:--:-- --:--:--\u00a0 2414\n{\n\u00a0 \"$schema\": \"api:standardResponse\",\n\u00a0 \"links\": &#91;\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"rel\": \"canonical\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"href\": \"https:\/\/SERVICE_ENDPOINT\/services\/adminsrvr\/v2\/logs\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"mediaType\": \"application\/json\"\n\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"rel\": \"self\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"href\": \"https:\/\/SERVICE_ENDPOINT\/services\/adminsrvr\/v2\/logs\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"mediaType\": \"application\/json\"\n\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"rel\": \"describedby\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"href\": \"https:\/\/SERVICE_ENDPOINT\/services\/adminsrvr\/v2\/metadata-catalog\/logs\",\n\u00a0\u00a0\u00a0\u00a0\u00a0 \"mediaType\": \"application\/schema+json\"\n\u00a0\u00a0\u00a0 }\n\u00a0 ],\n...<\/code><\/pre>\n\n\n\n<p>But our goal here is to implement a CI\/CD pipeline, so I wrote a very simple python script that runs some commands based in conditions (more latter), here I\u2019m using the requests library.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import requests\nimport json\nimport os\nfrom requests.auth import HTTPBasicAuth\nimport tarfile\nimport subprocess\nimport sys\ndeploymentUrl='SERVICE_ENDPOINT'\ndeploymentUser='USERNAME'\ndeploymentPasswd='PASSWORD'\nb_auth = HTTPBasicAuth(deploymentUser,deploymentPasswd)\n# r = requests.get('https:\/\/'+deploymentUrl+'\/services\/v2\/logs\/restapi', auth=b_auth,verify=False)\n# response = r.text\n# print(response)\ndef createCredential():\n\u00a0\u00a0\u00a0 headers = {'Content-type': 'application\/json', 'Accept':'application\/json'}\n\u00a0\u00a0\u00a0 with open('credential.json') as f:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 d=json.load(f)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(d)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 r = requests.post('https:\/\/'+deploymentUrl+'\/services\/v2\/credentials\/OracleGoldenGate\/con0122', auth=b_auth,verify=False,headers=headers, data=json.dumps(d))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response = r.json()\n\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0print(response)\u00a0\u00a0\u00a0\ndef createExtract(exName,prmFile):\n\u00a0\u00a0\u00a0 print('Creating Extract.....')\n\u00a0\u00a0\u00a0 headers = {'Content-type': 'application\/json', 'Accept':'application\/json'}\n\u00a0\u00a0\u00a0 with open(prmFile) as f:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 d=json.load(f)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(d)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 r = requests.post('https:\/\/'+deploymentUrl+'\/services\/v2\/extracts\/'+exName, auth=b_auth,verify=False,headers=headers, data=json.dumps(d),timeout=5)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response = r.json()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(response)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if r.status_code==200:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print('OK')\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print('Failed to run')\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(response)\n\u00a0\u00a0\u00a0 #response = r.headers\n\u00a0\u00a0 # print(response)\ndef updateExtract(exName,prmFile):\n\u00a0\u00a0\u00a0 print('Updating Extract.....')\n\u00a0\u00a0\u00a0 headers = {'Content-type': 'application\/json', 'Accept':'application\/json'}\n\u00a0\u00a0\u00a0 with open(prmFile) as f:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 d=json.load(f)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(d)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 r = requests.patch('https:\/\/'+deploymentUrl+'\/services\/v2\/extracts\/'+exName, auth=b_auth,verify=False,headers=headers, data=json.dumps(d),timeout=5)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response = r.json()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(response)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if r.status_code==200:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print('OK')\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print('Failed to run')\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(response)\n#createExtract()\n#if __name__ == '__main__':\n#\u00a0\u00a0\u00a0\u00a0 globals()&#91;sys.argv&#91;1]]()\n# print('Creating Credentials.....')\n# createCredential()\n# print('Creating Extract.....')\n# createExtract()\nif __name__ == '__main__':\n\u00a0\u00a0\u00a0 args = sys.argv\n\u00a0\u00a0\u00a0 globals()&#91;sys.argv&#91;1]](*args&#91;2:])<\/code><\/pre>\n\n\n\n<p>And you can call it passing parameters like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>python3 main.py createExtract EX1 extractESRC.json<\/code><\/pre>\n\n\n\n<p>Where extractESRC.json is a Json file with this content:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\"description\": \"criar ex\",\n\u00a0\u00a0\u00a0 \"credentials\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"domain\": \"OracleGoldenGate\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"alias\": \"con012\"\n\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0 \"intent\": \"Unidirectional\",\n\u00a0\u00a0\u00a0 \"status\": \"stopped\",\n\u00a0\u00a0\u00a0 \"begin\": \"now\",\n\u00a0\u00a0\u00a0 \"managedProcessSettings\": \"Default\",\n\u00a0\u00a0\u00a0 \"encryptionProfile\": \"LocalWallet\",\n\u00a0\u00a0\u00a0 \"source\": \"tranlogs\",\n\u00a0\u00a0\u00a0 \"registration\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"share\": true\n\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0 \"targets\": &#91;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"ee\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"remote\": false,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"path\": \"ESRC\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"sequence\": 0,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"sizeMB\": 500,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"offset\": 0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 ],\n\u00a0\u00a0\u00a0 \"config\": &#91;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"EXTRACT ESRC\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"USERIDALIAS con012 DOMAIN OracleGoldenGate\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"EXTTRAIL ESRC\/ee\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"TRANLOGOPTIONS SOURCE_OS_TIMEZONE GMT-3\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"table dbworld.*;\"\n\u00a0\u00a0\u00a0 ] }<\/code><\/pre>\n\n\n\n<p>Or <strong>python3 main.py createCredential cred2<\/strong> to create a credential with these parametes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n\"userid\":\"tanaka@192.168.56.1:1521\/dbsrc\",\n\"password\":\"abc123\"\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>OCI DevOps<\/strong><\/h2>\n\n\n\n<p>This part is heavily based on this article by Deepak Devadathan &nbsp;<a href=\"https:\/\/medium.com\/@xsgdkh\/infrastructure-provisioning-using-oci-devops-resource-manager-1e8a74d02a70\">https:\/\/medium.com\/@xsgdkh\/infrastructure-provisioning-using-oci-devops-resource-manager-1e8a74d02a70<\/a> ,&nbsp; so go there to read in details, and I can\u2019t forget to thanks Jose Neto that helped me with GitHub integration.<\/p>\n\n\n\n<p>My idea here is to have two pipelines that monitors my private repository, if I update and commit a file it will trigger the infrastructure pipeline, if the commit is in another file(ogg-api\/build_spec.yaml) it will trigger a REST API call, here is the workflow:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"483\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-23-1024x483.png\" alt=\"\" class=\"wp-image-1566\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-23-1024x483.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-23-300x141.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-23-768x362.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-23.png 1304w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>GitHub Configuration<\/strong><\/h2>\n\n\n\n<p>First, we need to setup a token in our GitHub, to do that, follow these steps:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"208\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-24-1024x208.png\" alt=\"\" class=\"wp-image-1567\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-24-1024x208.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-24-300x61.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-24-768x156.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-24.png 1053w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"860\" height=\"431\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-25.png\" alt=\"\" class=\"wp-image-1568\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-25.png 860w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-25-300x150.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-25-768x385.png 768w\" sizes=\"auto, (max-width: 860px) 100vw, 860px\" \/><\/figure>\n\n\n\n<p>And create a (software) Secret in your OCI Vault using this Token:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"511\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-28-1024x511.png\" alt=\"\" class=\"wp-image-1571\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-28-1024x511.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-28-300x150.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-28-768x383.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-28.png 1173w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"360\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-29-1024x360.png\" alt=\"\" class=\"wp-image-1572\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-29-1024x360.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-29-300x105.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-29-768x270.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-29.png 1053w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>We will use it to sync GitHub and OCI Code Repository.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>OCI DevOps<\/strong><\/h2>\n\n\n\n<p>Create a Connection under your DevOps project:<\/p>\n\n\n\n<p>External Connection &gt; Create External Connection:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"578\" height=\"471\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212601.png\" alt=\"\" class=\"wp-image-1574\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212601.png 578w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212601-300x244.png 300w\" sizes=\"auto, (max-width: 578px) 100vw, 578px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"811\" height=\"633\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212624.png\" alt=\"\" class=\"wp-image-1575\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212624.png 811w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212624-300x234.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212624-768x599.png 768w\" sizes=\"auto, (max-width: 811px) 100vw, 811px\" \/><\/figure>\n\n\n\n<p>And validate your connection:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"348\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212651-1024x348.png\" alt=\"\" class=\"wp-image-1576\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212651-1024x348.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212651-300x102.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212651-768x261.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212651.png 1245w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Go back to your DevOps project &gt; Code Repositories &gt; Mirror Repository and choose the external connection and your repository:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1023\" height=\"709\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212816.png\" alt=\"\" class=\"wp-image-1577\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212816.png 1023w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212816-300x208.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212816-768x532.png 768w\" sizes=\"auto, (max-width: 1023px) 100vw, 1023px\" \/><\/figure>\n\n\n\n<p>And wait for the first sync, you should be able to see the commits and files:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"973\" height=\"478\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212936.png\" alt=\"\" class=\"wp-image-1578\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212936.png 973w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212936-300x147.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212936-768x377.png 768w\" sizes=\"auto, (max-width: 973px) 100vw, 973px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"606\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212950-1024x606.png\" alt=\"\" class=\"wp-image-1579\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212950-1024x606.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212950-300x178.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212950-768x455.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-212950.png 1248w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>It\u2019s important to follow the Deepak Devadathan article before creating the next step.<\/p>\n\n\n\n<p>Here I have an UpdateStack and a Apply step inside a Build Pipeline called InfraDeployment:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"918\" height=\"653\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-213310.png\" alt=\"\" class=\"wp-image-1580\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-213310.png 918w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-213310-300x213.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-213310-768x546.png 768w\" sizes=\"auto, (max-width: 918px) 100vw, 918px\" \/><\/figure>\n\n\n\n<p>And a Pipeline called ProcessDeployment that will call GoldenGate APIs:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"860\" height=\"570\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-213350.png\" alt=\"\" class=\"wp-image-1581\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-213350.png 860w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-213350-300x199.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-213350-768x509.png 768w\" sizes=\"auto, (max-width: 860px) 100vw, 860px\" \/><\/figure>\n\n\n\n<p>Under your DevOps project, go to Triggers, so we will create the logic of pipeline trigger based on file commit.<\/p>\n\n\n\n<p>Choose a name and the Source must be GitHub(remember to choose your credential), and your action will be the InfraDeployment pipeline.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"388\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-30.png\" alt=\"\" class=\"wp-image-1583\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-30.png 624w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-30-300x187.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/figure>\n\n\n\n<p>I just want this pipeline running when I commit to ogg-api\/credential.yaml, so I put this name under Files to Include field, important: copy the Trigger URL and Secret, because it will be shown just once, and we will need this information to configure a WebHook in GitHub.<\/p>\n\n\n\n<p>Here my ogg-api\/credential.yaml file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>version: 0.1\ncomponent: build\ntimeoutInSeconds: 6000\nrunAs: root\nshell: bash\nenv:\n\u00a0 variables:\n\u00a0\u00a0\u00a0 deploymentUrl: \"DEPLOYMENT_ENDPOINT\"\n\u00a0\u00a0\u00a0 deploymentUser: \"USER\"\n\u00a0\u00a0\u00a0 deploymentPasswd: \"PASSWORD\"\n\u00a0 exportedVariables:\n\u00a0\u00a0\u00a0 - plan_job_id\n\u00a0\u00a0\u00a0 - commit_hash_short\nsteps:\n\u00a0 - type: Command\n\u00a0\u00a0\u00a0 timeoutInSeconds: 1200\n\u00a0\u00a0\u00a0 name: \"Create Extract\"\n\u00a0\u00a0\u00a0 command: |\n\u00a0\u00a0\u00a0\u00a0\u00a0 python3 main.py createCredential cred23\n\u00a0\u00a0\u00a0 onFailure:\n\u00a0\u00a0\u00a0\u00a0\u00a0 - type: Command\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 command: |\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 echo \"Handling Failure\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 echo \"Failure successfully handled\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 timeoutInSeconds: 40\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 runAs: root<\/code><\/pre>\n\n\n\n<p>Go to your GitHub repository &gt; Settings &gt; WebHooks and enter the captured information:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"492\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-214136-1024x492.png\" alt=\"\" class=\"wp-image-1585\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-214136-1024x492.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-214136-300x144.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-214136-768x369.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/Screenshot-2025-04-28-214136.png 1183w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Repeat it to your Process pipeline but in Files to Include specify the ogg-api\/credential.yaml<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Testing<\/strong><\/h2>\n\n\n\n<p>Ok, now we have everything in place and can test it, I will commit my terraform code to my GitHub, it will trigger our pipeline and get the code from OCI Code Repository:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"399\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-31.png\" alt=\"\" class=\"wp-image-1586\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-31.png 624w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2025\/04\/image-31-300x192.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>These days, automation is a no-brainer when working with cloud environments. Following best practices can really speed things up and get your product to market faster. In this post, I\u2019ll show you how to use Terraform, REST API, and OCI DevOps to build a CI\/CD pipeline. I\u2019ll cover the basics of each tool, so you\u2019ll [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1566,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"material-hide-sections":[],"footnotes":""},"categories":[55,19,48,18],"tags":[4,30,10,3],"class_list":["post-1555","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-api","category-cli","category-goldengate","category-terraform","tag-database","tag-devops","tag-oci","tag-oracle"],"_links":{"self":[{"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1555","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/comments?post=1555"}],"version-history":[{"count":19,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1555\/revisions"}],"predecessor-version":[{"id":1592,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1555\/revisions\/1592"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/media\/1566"}],"wp:attachment":[{"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/media?parent=1555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/categories?post=1555"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/tags?post=1555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}