<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Vous avez cherché ansible - dbi Blog</title>
	<atom:link href="https://www.dbi-services.com/blog/search/ansible/feed/rss2/" rel="self" type="application/rss+xml" />
	<link>https://www.dbi-services.com/blog/</link>
	<description></description>
	<lastBuildDate>Fri, 19 Jun 2026 12:44:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/05/cropped-favicon_512x512px-min-32x32.png</url>
	<title>Vous avez cherché ansible - dbi Blog</title>
	<link>https://www.dbi-services.com/blog/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Administer Oracle Database Appliance (ODA) with odacli and Ansible</title>
		<link>https://www.dbi-services.com/blog/administer-oracle-database-appliance-oda-with-odacli-and-ansible/</link>
					<comments>https://www.dbi-services.com/blog/administer-oracle-database-appliance-oda-with-odacli-and-ansible/#respond</comments>
		
		<dc:creator><![CDATA[Martin Bracher]]></dc:creator>
		<pubDate>Fri, 19 Jun 2026 12:44:40 +0000</pubDate>
				<category><![CDATA[Non classifié(e)]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=43293</guid>

					<description><![CDATA[<p>Introduction To administer an Oracle Database Appliance (ODA), you probably use the odacli commandline tool. The principle of this tool is to run jobs in background. Fire-and-forget&#8230; or Fire-and-poll This command returns a jobId (e.g. f1338963-87a2-4cb9-8a3e-06e104270203) and the job is executed in background. To see if this job is (sucessfully) completed, you have to poll [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/administer-oracle-database-appliance-oda-with-odacli-and-ansible/">Administer Oracle Database Appliance (ODA) with odacli and Ansible</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="h-introduction" class="wp-block-heading">Introduction</h2>



<p class="wp-block-paragraph">To administer an Oracle Database Appliance (ODA), you probably use the <code><a href="https://docs.oracle.com/en/engineered-systems/oracle-database-appliance/19.30/cmtrx/faqs-odacli-commands.html">odacli</a> </code>commandline tool.</p>



<p class="wp-block-paragraph">The principle of this tool is to run jobs in background. Fire-and-forget&#8230; or Fire-and-poll</p>



<pre class="wp-block-code"><code>odacli update-repository -f "/tmp/odacli-dcs-19.30.0.0.0-260210-GI-19.30.0.0.zip"</code></pre>



<p class="wp-block-paragraph">This command returns a jobId (e.g. f1338963-87a2-4cb9-8a3e-06e104270203) and the job is executed in background. To see if this job is (sucessfully) completed, you have to poll for the above jobId and wait for Status: Success.</p>



<pre class="wp-block-code"><code>odacli describe-job -i f1338963-87a2-4cb9-8a3e-06e104270203
watch -n 2 odacli describe-job -i f1338963-87a2-4cb9-8a3e-06e104270203</code></pre>



<h2 id="h-automation-with-ansible" class="wp-block-heading">Automation with Ansible</h2>



<p class="wp-block-paragraph">For automation, e.g. with Ansible, that is not optimal. We have to implement a polling mechanism for the odacli commands. </p>



<p class="wp-block-paragraph">For example. we will add new software to the ODA-repository.  (version=19.30, software_zip=/tmp/odacli-dcs-19.30.0.0.0-260210-GI-19.30.0.0.zip)</p>



<p class="wp-block-paragraph">First of all, we run odacli to create the job to add the software to the  repository and extract the jobId from the output.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
  - name: import software in repository
    ansible.builtin.shell: |
      /opt/oracle/dcs/bin/odacli describe-dbsystem-image -j \
        | jq -e &#039;.&#x5B;].dbSystemImageComponents&#x5B;]|select(.componentName==&quot;DB&quot;)|.availableVersions&#x5B;]|select(startswith(&quot;{{version2}}&quot;)) &#039; \
        |grep  {{version2}} &gt;&amp;2 &amp;&amp; echo &#039;ALREADY_INSTALLED&#039; &amp;&amp; exit 0
      /opt/oracle/dcs/bin/odacli update-repository -f &quot;{{software_zip}}&quot;
    register: repo
    changed_when: &quot;&#039;ALREADY_INSTALLED&#039; not in repo.stdout&quot;

  - name: set job-id
    set_fact:
      jobid: &quot;{{ (repo.stdout | from_json).jobId }}
    when: &quot;&#039;ALREADY_INSTALLED&#039; not in repo.stdout&quot;
</pre></div>


<p class="wp-block-paragraph">Hint: the 1st command is to check if this software is already imported</p>



<p class="wp-block-paragraph">Now, we can poll the job until it is completed. Ansible is optimized to work with json. So we will enforce odacli to return the output in json format (-j):</p>



<pre class="wp-block-code"><code>/opt/oracle/dcs/bin/odacli describe-job -i f1338963-87a2-4cb9-8a3e-06e104270203 -j
{
  "jobId" : "f1338963-87a2-4cb9-8a3e-06e104270203",
  "status" : "Created",
  "message" : "/tmp/odacli-dcs-19.30.0.0.0-260210-GI-19.30.0.0.zip",
  "reports" : &#091; ],
  "createTimestamp" : "February 24, 2026 13:58:30 PM CET",
  "resourceList" : &#091; ],
  "description" : "Repository Update",
  "updatedTime" : "February 24, 2026 13:58:30 PM CET",
  "jobType" : null,
  "cpsMetadata" : null
}</code></pre>



<p class="wp-block-paragraph">For polling, we can use the ansible loop control, see the <a href="https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_loops.html#retrying-a-task-until-a-condition-is-met">Ansible documentatioon</a></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
  - name: check until job completed
    ansible.builtin.shell: /opt/oracle/dcs/bin/odacli describe-job -j -i {{jobid}}
    register: check_status
    until: &quot;(check_status.stdout|from_json).status == &#039;Success&#039;&quot;
    retries: 10
    delay: 8
    changed_when: false
    when: &quot;&#039;ALREADY_INSTALLED&#039; not in repo.stdout&quot;
</pre></div>


<p class="wp-block-paragraph">That means, Ansible will run the command every 8 seconds until status Success is returned (Success) or after 10 attemts (Failed)</p>



<pre class="wp-block-code"><code>TASK &#091;check until job completed] ************************************************************************
FAILED - RETRYING: check until job completed (10 retries left).
FAILED - RETRYING: check until job completed (9 retries left).
FAILED - RETRYING: check until job completed (8 retries left).
FAILED - RETRYING: check until job completed (7 retries left).
FAILED - RETRYING: check until job completed (6 retries left).
FAILED - RETRYING: check until job completed (5 retries left).
FAILED - RETRYING: check until job completed (4 retries left).
ok: &#091;server01]</code></pre>



<h3 id="h-re-usability-with-roles" class="wp-block-heading">Re-usability with roles</h3>



<p class="wp-block-paragraph">For re-usablility, I recommend to move the job-polling to a role, so that it can be used for all asynchronous jobs</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
# roles/odacli_job/tasks/main.yml
  - name: set job-id
    set_fact:
      jobid: &quot;{{ (job_stdout | from_json).jobId |default(&#039;&#039;) }}&quot;
    when: job_stdout|default(&#039;&#039;) != &#039;&#039;
  - debug: var=jobid

  - name: check until repo job completed
    ansible.builtin.shell: /opt/oracle/dcs/bin/odacli describe-job -j -i {{jobid}}
    register: check_status
    failed_when: false
    until: &quot;(check_status.stdout|from_json).status == &#039;Success&#039; or (check_status.stdout|from_json).status == &#039;Failure&#039;&quot;
    retries: &quot;{{retries}}&quot;
    delay:   &quot;{{delay}}&quot;
    changed_when: false
</pre></div>


<p class="wp-block-paragraph">The role can be used as follows:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
  - name: include role to poll job
    include_role:
      role: odacli_job
    when: &quot;&#039;ALREADY_INSTALLED&#039; not in repo.stdout&quot;
    vars:
      job_stdout: repo.stdout 
      retries: 50
      delay: 3
</pre></div>


<p class="wp-block-paragraph">The job to poll can be specified by variable &#8220;jobid&#8221;, or you can provide the json-output of launching the job via &#8220;job_stdout&#8221;, then the role extracts the jobid</p>



<p class="wp-block-paragraph">After the import of the software (you will see it in /opt/oracle/oak/pkgrepos/orapkgs/clones/), you can now deploy an ORACLE_HOME with it. For that, we can use the same role to poll this asynchronous job:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
  - name: create database home
    ansible.builtin.shell: |
      /opt/oracle/dcs/bin/odacli create-dbhome -j -v {{version}}
    register: home

  - name: include role to poll job
    include_role:
      role: odacli_job
    vars:
      job_stdout: home.stdout
      retries: 80
      delay: 10
</pre></div>


<h3 id="h-errorhandling" class="wp-block-heading">Errorhandling</h3>



<p class="wp-block-paragraph">What is not done in the role is the error-handling. It is up to you to define an adequate error-handling. You will get the result of the asynchronous job in the variable check_status.stdout which is of json format. </p>



<pre class="wp-block-code"><code>(check_status.stdout|from_json).status</code></pre>



<p class="wp-block-paragraph">If the status is </p>



<ul class="wp-block-list">
<li>&#8220;Success&#8221;, it is OK</li>



<li>&#8220;Failure&#8221;, it is not OK</li>



<li>Any other value (e.g. &#8220;Created&#8221;), you got a timeout (&gt;retries*timeout sec.), then the result it is unknown (maybe the job completes at a later time, sucessful or not).</li>
</ul>



<p class="wp-block-paragraph"></p>
<p>L’article <a href="https://www.dbi-services.com/blog/administer-oracle-database-appliance-oda-with-odacli-and-ansible/">Administer Oracle Database Appliance (ODA) with odacli and Ansible</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/administer-oracle-database-appliance-oda-with-odacli-and-ansible/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Customer case study &#8211; automating SQL Server TLS Encryption with Ansible and Certificates (Architecture)</title>
		<link>https://www.dbi-services.com/blog/customer-case-study-automating-sql-server-tls-encryption-with-ansible-and-certificates-architecture/</link>
					<comments>https://www.dbi-services.com/blog/customer-case-study-automating-sql-server-tls-encryption-with-ansible-and-certificates-architecture/#respond</comments>
		
		<dc:creator><![CDATA[Amine Haloui]]></dc:creator>
		<pubDate>Fri, 15 May 2026 19:35:21 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=44594</guid>

					<description><![CDATA[<p>When working with SQL Server environments, securing client connections can become an important requirement, especially when TLS encryption must be implemented using certificates. In this context, a customer asked us to develop an Ansible playbook and role to automate the configuration of TLS for SQL Server. The certificates are generated from the customer PKI and [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/customer-case-study-automating-sql-server-tls-encryption-with-ansible-and-certificates-architecture/">Customer case study &#8211; automating SQL Server TLS Encryption with Ansible and Certificates (Architecture)</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">When working with SQL Server environments, securing client connections can become an important requirement, especially when TLS encryption must be implemented using certificates. In this context, a customer asked us to develop an Ansible playbook and role to automate the configuration of TLS for SQL Server. The certificates are generated from the customer PKI and provided as PEM files containing the server certificate, the private key, and the certificate chain.</p>



<p class="wp-block-paragraph">However, some extractions and conversions are required before these certificates can be used on Windows and configured for SQL Server.</p>



<p class="wp-block-paragraph">Here, the idea is to propose a solution (the architecture) that prepares the certificate, imports it on the SQL Server host, and configures SQL Server to use it.</p>



<p class="wp-block-paragraph">We will also see how to separate the preparation and activation steps in order to reduce the impact on the SQL Server service.</p>



<p class="wp-block-paragraph">In this blog post, we will describe the global approach and the Ansible logic used to implement certificate-based TLS encryption for SQL Server.</p>



<h2 class="wp-block-heading" id="h-implementation-logic">Implementation logic</h2>



<p class="wp-block-paragraph">Before configuring TLS encryption on SQL Server, the first point was to understand the certificate format provided by the customer PKI.</p>



<p class="wp-block-paragraph">In our case, the generated file is a &lt;machine&gt;.pem file. This file contains the server certificate used for TLS, the private key and the certificate chain with the intermediate and root certificates.</p>



<p class="wp-block-paragraph">As this format cannot be directly used as-is on the Windows side for SQL Server, some extraction and conversion steps are required.</p>



<p class="wp-block-paragraph">The general idea is to use the Ansible control node as a working area.</p>



<p class="wp-block-paragraph">The PEM file is first copied into a temporary folder where the different parts of the certificate are extracted:</p>



<ul class="wp-block-list">
<li>the leaf certificate</li>



<li>the intermediate certificate</li>



<li>the root certificate</li>



<li>the private key</li>
</ul>



<p class="wp-block-paragraph">These elements are then used to build a PFX file which can be imported on the Windows SQL Server host.</p>



<p class="wp-block-paragraph">The PFX is installed in the LocalMachine\My certificate store while the intermediate and root certificates are imported into the appropriate Windows certificate stores.</p>



<p class="wp-block-paragraph">The implementation has been designed around three different execution modes: stage, activate, and full.</p>



<p class="wp-block-paragraph">The stage mode is used to prepare the certificate without any impact on the SQL Server service. It copies the PEM file, performs the extractions, builds the PFX file, copies it to the managed Windows node and imports the certificates into the Windows certificate stores. No registry change is performed, and the SQL Server service is not restarted. This mode is useful when we want to prepare the server in advance before switching SQL Server to the new certificate.</p>



<p class="wp-block-paragraph">The activate mode assumes that the certificate is already present on the Windows server. Its role is to configure SQL Server to use the installed certificate and depending on the selected option, restart the SQL Server service or leave the change pending until the next planned reboot.</p>



<p class="wp-block-paragraph">This can be useful when the certificate activation must be aligned with an existing maintenance window, for example during monthly OS patching.</p>



<p class="wp-block-paragraph">The full mode executes the complete configuration from end to end. It performs the extraction and conversion steps, imports the certificates, grants the required permissions, configures SQL Server to use the expected certificate, and restarts the SQL Server service only if required. To avoid unnecessary impact, the role relies on the certificate thumbprint. If the expected certificate is already configured, no change is applied and the SQL Server service is not restarted. This behavior is important for idempotency.</p>



<p class="wp-block-paragraph">For example, if the full mode is executed after an activate mode, nothing should be changed if the certificate is already the correct one. The same logic applies if the playbook is executed by mistake while the certificate has not been renewed.</p>



<p class="wp-block-paragraph">Another point to manage is the restart of the SQL Server service. SQL Server loads the certificate configuration when the service starts. Therefore, when a new certificate is configured, the change is only effective after a restart of the SQL Server service.</p>



<p class="wp-block-paragraph">For this reason the role should provide an option to control whether the restart is performed immediately or postponed to the next planned reboot.</p>



<p class="wp-block-paragraph">We also have to consider DNS aliases. The standard use case is to generate a certificate containing at least the short name and the FQDN of the SQL Server host in the subjectAltName. If DNS aliases are used by client applications, they can also be added to the certificate SAN.</p>



<p class="wp-block-paragraph">For example:</p>



<pre class="wp-block-code"><code>&#091;alt_names]
DNS.1 = A-WS2022-2.lab.local
DNS.2 = A-WS2022-2</code></pre>



<p class="wp-block-paragraph">Finally, the customer confirmed that the private key included in the PEM file is not encrypted.</p>



<p class="wp-block-paragraph">This simplifies the conversion process to PFX, but it also means that the PEM file must be handled carefully during the Ansible execution, especially in temporary folders and during file transfers. With this approach, the role provides a controlled way to prepare, activate, or fully configure TLS encryption for SQL Server while keeping the impact on the SQL Server service under control.</p>



<h2 class="wp-block-heading" id="h-logical-workflow">Logical workflow</h2>



<p class="wp-block-paragraph">The complete workflow can be represented as follows:</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="672" height="1024" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/05/I3_Wite_Background-672x1024.jpeg" alt="" class="wp-image-44607" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/05/I3_Wite_Background-672x1024.jpeg 672w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/05/I3_Wite_Background-197x300.jpeg 197w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/05/I3_Wite_Background-768x1169.jpeg 768w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/05/I3_Wite_Background-1009x1536.jpeg 1009w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/05/I3_Wite_Background-1345x2048.jpeg 1345w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/05/I3_Wite_Background-scaled.jpeg 1681w" sizes="(max-width: 672px) 100vw, 672px" /></figure>



<h2 class="wp-block-heading" id="h-architecture-summary">Architecture summary</h2>



<p class="wp-block-paragraph">The certificate manipulation is performed on the Ansible control node.</p>



<p class="wp-block-paragraph">The Windows certificate import and SQL Server configuration are performed on the managed Windows SQL Server host.</p>



<p class="wp-block-paragraph">This separation is useful because the PEM processing and PFX generation are handled with Linux tools such as OpenSSL while the certificate installation, private key permissions, registry configuration and SQL Server restart are handled through Windows modules and PowerShell. The design also supports a controlled deployment approach.</p>



<p class="wp-block-paragraph">The certificate can first be staged without service impact then activated later during a maintenance window.</p>



<p class="wp-block-paragraph">The full mode can be used when the complete implementation must be executed in a single run. The use of the certificate thumbprint is important for idempotency. It allows the role to detect whether SQL Server is already configured with the expected certificate and avoids unnecessary service restarts when no change is required.</p>



<h2 class="wp-block-heading" id="h-remarks">Remarks</h2>



<p class="wp-block-paragraph">For certain reasons we do not disclose the code of the created role.</p>



<p class="wp-block-paragraph">Thank you. <a href="https://www.linkedin.com/in/amine-haloui-76968056/">Amine Haloui</a></p>
<p>L’article <a href="https://www.dbi-services.com/blog/customer-case-study-automating-sql-server-tls-encryption-with-ansible-and-certificates-architecture/">Customer case study &#8211; automating SQL Server TLS Encryption with Ansible and Certificates (Architecture)</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/customer-case-study-automating-sql-server-tls-encryption-with-ansible-and-certificates-architecture/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Beyond TDE and TLS: Bridging the Data Security Governance Gap in Lower Environments</title>
		<link>https://www.dbi-services.com/blog/tde-tls-data-security-governance-gap-in-lower-environments/</link>
					<comments>https://www.dbi-services.com/blog/tde-tls-data-security-governance-gap-in-lower-environments/#respond</comments>
		
		<dc:creator><![CDATA[Louis Tochon]]></dc:creator>
		<pubDate>Mon, 27 Apr 2026 20:21:34 +0000</pubDate>
				<category><![CDATA[Delphix]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[delphix]]></category>
		<category><![CDATA[encryption]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=43973</guid>

					<description><![CDATA[<p>Why one layer is never enough, why dev environments are your biggest GDPR gap, and how to industrialize their governance.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/tde-tls-data-security-governance-gap-in-lower-environments/">Beyond TDE and TLS: Bridging the Data Security Governance Gap in Lower Environments</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full is-style-rounded"><img decoding="async" width="1408" height="768" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/04/Gemini_Generated_Image_8vt09b8vt09b8vt0.png" alt="Conceptual diagram of a secure data pipeline showing production data passing through a governance engine to anonymized dev and staging environments." class="wp-image-44034" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/04/Gemini_Generated_Image_8vt09b8vt09b8vt0.png 1408w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/04/Gemini_Generated_Image_8vt09b8vt09b8vt0-300x164.png 300w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/04/Gemini_Generated_Image_8vt09b8vt09b8vt0-1024x559.png 1024w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/04/Gemini_Generated_Image_8vt09b8vt09b8vt0-768x419.png 768w" sizes="(max-width: 1408px) 100vw, 1408px" /></figure>



<h2 class="wp-block-heading" id="h-the-multi-layered-threat-why-one-tool-is-never-enough">The Multi-Layered Threat: Why One Tool is Never Enough</h2>



<p class="wp-block-paragraph">We’ve all left the key in our bike lock at least once. This simple human oversight makes the heaviest chain irrelevant and we often see the exact same logic applied to data environments. Most organizations spend months hardening their production core but leave the keys in the locks of the <em>dev</em> and <em>staging </em>systems that sit right next to it. </p>



<p class="wp-block-paragraph">The numbers back this up. While 91% of organizations are concerned about their exposure across lower environments, a staggering <span style="text-decoration: underline"><strong>86%</strong> <strong>still allow data compliance exceptions in non-production</strong></span>. This gap between concern and action has real consequences: more than half of these organizations have already experienced a breach or audit failure in their testing and development systems (<a href="https://www.prnewswire.com/news-releases/delphixs-state-of-data-compliance-and-security-report-reveals-54-of-organizations-have-experienced-data-breaches-or-theft-in-non-production-environments-302225897.html">PR Newswire</a>).</p>



<p class="wp-block-paragraph">Effective security is rarely a single-layer problem. Between the stolen backup that lands in the wrong hands, the analyst running a <code>SELECT</code> on a table they probably shouldn&#8217;t see, and the packet quietly crossing an unsecured network segment, <a href="https://www.fortinet.com/resources/cyberglossary/attack-surface">the attack surface</a> is wide, and no single mechanism covers it all.</p>



<p class="wp-block-paragraph">Transport Layer Security (TLS), Transparent Data Encryption (TDE), symmetric encryption, dynamic masking, row-level security, data anonymization: for most RDBMS, the options exist and they work. Most teams already have access to at least one of them. The real challenge isn&#8217;t finding a solution; it&#8217;s understanding what each one actually protects, where it breaks down, and whether it survives contact with a production environment.</p>



<h2 class="wp-block-heading" id="h-shadow-environments-the-weakest-link-in-your-data-chain">Shadow Environments: The Weakest Link in Your Data Chain</h2>



<p class="wp-block-paragraph">Here is the uncomfortable truth: non-production environments are often where security policies are quietly buried. It starts with a backup restored without encryption, or real customer data seeding a dev database <em>&#8220;just for a quick test</em>&#8220;.</p>



<p class="wp-block-paragraph">The fundamental problem is that most protections assume a controlled environment. Encryption can be bypassed by someone with the right credentials. Masking can be misconfigured. Row-level security doesn&#8217;t help much when the whole database is sitting on a developer&#8217;s laptop.</p>



<h2 class="wp-block-heading" id="h-technical-trade-offs-finding-your-strategic-fit">Technical Trade-offs: Finding Your Strategic Fit</h2>



<p class="wp-block-paragraph">To make this reasoning concrete, the table below maps six core techniques against the operational criteria that define their success. The goal isn&#8217;t to pick a favorite tool, but to identify which combination actually addresses your specific vulnerabilities.</p>



<figure class="wp-block-table alignfull is-style-stripes"><table><tbody><tr><td class="has-text-align-center" data-align="center"></td><td class="has-text-align-center" data-align="center">Physical File Theft</td><td class="has-text-align-center" data-align="center">Read Access (SELECT)</td><td class="has-text-align-center" data-align="center">Network Sniffing</td><td class="has-text-align-center" data-align="center">Performance Impact</td><td class="has-text-align-center" data-align="center">Granularity</td><td class="has-text-align-center" data-align="center">Applicable in Prod <br>(live data)</td><td class="has-text-align-center" data-align="center">Applicable in DEV</td></tr><tr><td class="has-text-align-center" data-align="center">TLS</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center">Data packet</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td class="has-text-align-center" data-align="center">TDE</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center">Column<br>Tablespace<br>Datafile</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td class="has-text-align-center" data-align="center">Symmetric encryption (applicative)</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center">Field<br>Value</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td class="has-text-align-center" data-align="center">Dynamic Masking</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center">Column</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td class="has-text-align-center" data-align="center">Row-level security</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center">Row</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td class="has-text-align-center" data-align="center">Data anonymization</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center">Field<br>Column</td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td class="has-text-align-center" data-align="center"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr></tbody></table></figure>



<ul class="wp-block-list">
<li><a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">TLS </a>protects data in motion. The moment a packet leaves a server, TLS ensures anyone intercepting it sees encrypted noise. What it doesn&#8217;t do is equally important: it has no opinion about who queries your database or what&#8217;s stored on disk. Once the data arrives, TLS&#8217;s job is done.<br>TLS is now the industry standard for securing data in motion.<br><em>(SQL Server technical blog about TLS <a href="https://www.dbi-services.com/blog/sql-server-how-to-see-your-enable-security-protocols-tls-ssl-dtls-with-a-tsql-query/">here</a>)</em></li>



<li><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/asoag/introduction-to-transparent-data-encryption.html">TDE </a>encrypts the physical files that make up your database (data files, log files, backups), so that anyone who gets their hands on them without the encryption key can&#8217;t read them. The performance impact is a negligible overhead; in fact, Microsoft for example enables TDE <strong>by default</strong> for all its cloud-based databases.<br><em>(PostgreSQL technical blog about TDE <a href="https://www.dbi-services.com/blog/commercial-postgresql-distributions-with-tde-1-fujitsu-enterprise-postgres-1-setup/">here</a>)</em><br>However, deploying TDE in development is a security best practice, but it quickly becomes an operational nightmare for environment refreshes, especially if you want to use distinct certificates to avoid leaking production secrets into lower environments.</li>



<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/security/encryption/always-encrypted-database-engine?view=sql-server-ver17">Symmetric encryption</a> is field-level encryption applied directly in the application layer. Unlike TDE, it survives a legitimate SELECT; even a user with full read access sees <a href="https://en.wikipedia.org/wiki/Ciphertext">ciphertext </a>unless they hold the applicative key. The tradeoff is performance: encrypting and decrypting at scale adds up quickly.<br><em>(MongoDB technical blog about Client-side Field Level Encryption <a href="https://www.geeksforgeeks.org/mongodb/mongodb-client-side-field-level-encryption/">here</a>)</em></li>



<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/security/dynamic-data-masking?view=sql-server-ver17">Dynamic masking</a> doesn&#8217;t encrypt anything. It intercepts query results and replaces sensitive values with masked equivalents based on the user&#8217;s role. Fast, lightweight, zero application changes required. The catch: it only controls what&#8217;s displayed, not what&#8217;s stored. A user with sufficient privileges can bypass it entirely.<br><em>(SQL Server technical blog about dynamic masking <a href="https://www.mssqltips.com/sqlservertip/7887/dynamic-data-masking-in-sql-server-for-sensitive-data-protection/">here</a>)</em></li>



<li><a href="https://database.guide/understanding-row-level-security-rls/">Row-Level Security </a>enforces access at the row level directly inside the database engine. Users see only the rows they&#8217;re allowed to see, regardless of how the query is written. No application changes, no trust placed in the calling layer. The policy lives in the database and applies universally.<br><em>(Oracle technical blog about Virtual Private Database <a href="https://www.dbi-services.com/blog/oracle-virtual-private-database/">here</a>)</em></li>



<li><a href="https://en.wikipedia.org/wiki/Data_anonymization">Data anonymization</a> doesn&#8217;t protect sensitive data, <strong><span style="text-decoration: underline">it eliminates it</span></strong>. Real values are replaced with realistic but fictional equivalents (<a href="https://www.ibm.com/think/topics/synthetic-data">synthetic data</a>), permanently and irreversibly. No encryption key to steal, no masking rule to bypass. Whatever leaks simply isn&#8217;t sensitive anymore. This is why anonymization is the only control that makes unconditional sense in non-production environments. A stolen backup, a misconfigured SELECT, a sniffed packet: <strong>none</strong> of it matters if the data was anonymized before it ever reached a staging environment. We covered how to implement it in practice in <a href="https://www.dbi-services.com/blog/data-anonymization-as-a-service-with-delphix-continuous-compliance/" id="https://www.dbi-services.com/blog/data-anonymization-as-a-service-with-delphix-continuous-compliance/">a previous post</a></li>
</ul>



<h2 class="wp-block-heading" id="h-ownership-gaps-the-security-no-man-s-land">Ownership Gaps: The Security No Man&#8217;s Land</h2>



<p class="wp-block-paragraph">We are shifting from a technical challenge to a human and organizational one. The security landscape moves so fast that the struggle of mastering every layer has become overwhelming.</p>



<p class="wp-block-paragraph">This complexity is where governance goes to die. Infrastructure teams build the walls, developers write the code, and DBAs manage the house, but the accountability for the data itself often falls through the cracks. The most dangerous gap isn&#8217;t a missing feature; it’s the absence of a governance model strong enough to stop the game of hot potato and force a cross-domain ownership of security.</p>



<p class="wp-block-paragraph">The CISO&#8217;s role in this landscape is not to master every technical layer, it is to force the question of ownership into the open. Who signs off on what data enters a non-production environment? Who is accountable when a dev database is restored without encryption? Who audits that masking policies are still effective after a release?</p>



<p class="wp-block-paragraph">Without explicit answers to these questions, security becomes a game of assumptions. Every team assumes another layer is holding. And the gaps compound silently, until they don&#8217;t.</p>



<h2 class="wp-block-heading">From Handcrafted Scripts to Enterprise Platforms</h2>



<p class="wp-block-paragraph">Every technique in this table can be implemented on a spectrum, from a carefully written script to a fully automated enterprise solution. The right choice depends on your scale, your team, and how much operational overhead you can realistically absorb.</p>



<ul class="wp-block-list">
<li><strong>TLS certificate deployment:</strong> you can generate and rotate certificates manually, instance by instance. Or you can automate the entire lifecycle using <strong><span style="text-decoration: underline">Ansible</span></strong> against an internal PKI with a consistent and auditable way that is invisible to the teams consuming it. The security outcome is identical; the operational cost is not.</li>



<li><strong>Data anonymization:</strong> a custom script that detects <a href="https://www.cloudflare.com/learning/privacy/what-is-pii/">PII </a>columns and replaces values with masked data works well at small scale. The challenge appears when your data spans multiple database engines (SQL Server, Oracle, PostgreSQL, &#8230;) and when anonymized values need to remain consistent across foreign keys and referential constraints. Replacing a customer ID in one table while leaving it intact in another isn&#8217;t anonymization, it&#8217;s a GDPR incident waiting to happen. Solutions like <a href="https://help.delphix.com/cc/current/content/continuous_compliance_home.htm">Delphix Continuous Compliance</a> handle cross-DBMS consistency, constraint awareness, and sensitive field detection out of the box, turning a fragile hand-rolled process into a governed, repeatable and auditable one.</li>



<li><strong>Dynamic masking and row-level security:</strong> defining a handful of policies manually in SSMS is perfectly reasonable for a contained environment. Automating policy deployment across environments and instances is a different challenge entirely. It is a level of scale where ad-hoc scripts quickly become a liability.</li>
</ul>



<h2 class="wp-block-heading" id="h-conclusion-moving-beyond-security-by-accident">Conclusion: Moving Beyond Security by Accident</h2>



<p class="wp-block-paragraph">Security is not a one-time project. It is an operational discipline that requires the same rigor in a developer&#8217;s sandbox as it does in production, and that rigor has to be enforced <span style="text-decoration: underline"><strong>by design</strong></span>, not by goodwill.</p>



<p class="wp-block-paragraph">Most breaches in non-production environments don&#8217;t happen because a tool failed. They happen because nobody owned the decision to use it in the first place.</p>



<p class="wp-block-paragraph">At <strong>dbi services</strong>, we help organizations move from fragile, handcrafted scripts to governed, auditable architectures across every environment, every database engine, and every team. </p>



<p class="wp-block-paragraph"><strong>Because under GDPR, <span style="text-decoration: underline">one</span> incident is all it takes to make ownership everyone&#8217;s problem.</strong></p>
<p>L’article <a href="https://www.dbi-services.com/blog/tde-tls-data-security-governance-gap-in-lower-environments/">Beyond TDE and TLS: Bridging the Data Security Governance Gap in Lower Environments</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/tde-tls-data-security-governance-gap-in-lower-environments/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>OTDS &#8211; Installation of Replicas fail if the OT Admin password is too long?</title>
		<link>https://www.dbi-services.com/blog/otds-installation-of-replicas-fail-if-the-ot-admin-password-is-too-long/</link>
					<comments>https://www.dbi-services.com/blog/otds-installation-of-replicas-fail-if-the-ot-admin-password-is-too-long/#respond</comments>
		
		<dc:creator><![CDATA[Morgan Patou]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 11:36:04 +0000</pubDate>
				<category><![CDATA[Enterprise content management]]></category>
		<category><![CDATA[Documentum]]></category>
		<category><![CDATA[OTDS]]></category>
		<category><![CDATA[Password]]></category>
		<category><![CDATA[primary]]></category>
		<category><![CDATA[replica]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=43629</guid>

					<description><![CDATA[<p>For simplicity, in this blog, I will refer to the first OTDS instance as the &#8220;Primary&#8221; (the synchronization master host, installed with ISREPLICA_TOPOLOGY=0=FALSE) and any additional instances as &#8220;Replicas&#8221; (installed with ISREPLICA_TOPOLOGY=1=TRUE). Over the past few years, I have installed and worked on around 20–30 different OTDS environments, some with a single instance and others [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/otds-installation-of-replicas-fail-if-the-ot-admin-password-is-too-long/">OTDS &#8211; Installation of Replicas fail if the OT Admin password is too long?</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">For simplicity, in this blog, I will refer to the first OTDS instance as the &#8220;<em><strong>Primary</strong></em>&#8221; (the synchronization master host, installed with <em><strong>ISREPLICA_TOPOLOGY=0=FALSE</strong></em>) and any additional instances as &#8220;<em><strong>Replicas</strong></em>&#8221; (installed with <em><strong>ISREPLICA_TOPOLOGY=1=TRUE</strong></em>). Over the past few years, I have installed and worked on around 20–30 different OTDS environments, some with a single instance and others with multiple instances (HA). Overall, it is not a bad piece of software, even though it could use improvements in certain areas (e.g.: c.f. <a href="https://www.dbi-services.com/blog/dctm-mfa-non-mfa-within-otds-based-on-target-applications/" target="_blank" rel="noreferrer noopener">this blog</a>). However, it was only after I started installing a few Replicas on recent OTDS versions (using a database backend instead of OpenDJ) that I encountered a rather unusual issue.</p>



<h2 class="wp-block-heading" id="h-1-otds-replica-installation-failure">1. OTDS Replica installation failure</h2>



<p class="wp-block-paragraph">Single-instance installations using the silent properties file were always successful, and most multi-instance installations worked as well. However, I encountered a very specific issue twice: the Primary instance would install successfully, but the Replica installation would fail with an error stating &#8220;<em><strong>parameter JDBC_CONNECTION_STRING not defined</strong></em>&#8220;. Since everything runs in automated environments (Kubernetes or Ansible), I knew it was not a human error. When comparing the silent properties files, everything looked correct. The file used on the Primary was exactly the same as the one used on the Replica, except for &#8220;<em><strong>ISREPLICA_TOPOLOGY=0</strong></em>&#8221; and &#8220;<em><strong>ENCRYPTION_KEY=</strong></em>&#8221; on the Primary versus &#8220;<em><strong>ISREPLICA_TOPOLOGY=1</strong></em>&#8221; and &#8220;<em><strong>ENCRYPTION_KEY=XXXXXXX</strong></em>&#8221; on the Replica.</p>



<p class="wp-block-paragraph">This is the expected configuration. A Replica needs to take the value of &#8220;<em><strong>directory.bootstrap.CryptSecret</strong></em>&#8221; from the &#8220;<em><strong>otds.properties</strong></em>&#8221; file of the Primary and use that value for &#8220;<em><strong>ENCRYPTION_KEY</strong></em>&#8220;. Therefore, when you install the Primary instance, the value remains empty because nothing is installed yet. During the Replica installation, the automation retrieves this value and populates the parameter accordingly. But then why would the Primary installation succeed while the Replica fails when using the exact same silent properties file? Quite strange, right? First of all, I tried running the installer manually (outside of Kubernetes or Ansible) to see whether additional details would appear in the console:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
&#x5B;tomcat@otds-1 workspace_otds]$ /app/scripts/workspace_otds/otds/setup -qbi -rf /app/scripts/workspace_otds/otds/silent.properties

OpenText Directory Services 24.4.0

Error, parameter JDBC_CONNECTION_STRING not defined.
&#x5B;tomcat@otds-1 workspace_otds]$
</pre></div>


<h2 class="wp-block-heading" id="h-2-going-further-into-the-installation-logs">2. Going further into the installation logs</h2>



<p class="wp-block-paragraph">The generated log file was not really helpful either:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [10,11,12,21,27,28,42,43]; title: ; notranslate">
&#x5B;tomcat@otds-1 workspace_otds]$ cat otds.log
...
2025-08-08  6:38:40 chmod ran successfully on /etc/opentext/unixsetup
2025-08-08  6:38:40 Setting environment variable &quot;ACTION&quot; to &quot;-1&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;UPGRADE&quot; to &quot;0&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;PATCH&quot; to &quot;0&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;INSTALLED&quot; to &quot;0&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;INSTALLEDVERSION&quot; to &quot;0.0.0&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;PRODUCTINSTANCE&quot; to &quot;1&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;PRODUCTVERSION&quot; to &quot;24.4.0.4503&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;PRODUCTNAME&quot; to &quot;OpenText Directory Services&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;PRODUCTID&quot; to &quot;OTDS&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;PATCHVERSION&quot; to &quot;0&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;ROOTUSER&quot; to &quot;0&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;Main_INSTALLED&quot; to &quot;-1&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;INST_GROUP&quot; to &quot;tomcat&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;INST_USER&quot; to &quot;tomcat&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;INSTALL_DIR&quot; to &quot;/app/tomcat/app_data/otds&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;TOMCAT_DIR&quot; to &quot;/app/tomcat&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;PRIMARY_FQDN&quot; to &quot;otds-1.otds.otdsdev.svc.cluster.local&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;ISREPLICA_TOPOLOGY&quot; to &quot;1&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;IMPORT_DATA&quot; to &quot;0&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;OTDS_PASS&quot; to &quot;*****&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;ENCRYPTION_KEY&quot; to &quot;mqLgucZ8UIUnNcLwjwmhNw==&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;MIGRATION_OPENDJ_URL&quot; to &quot;&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;MIGRATION_OPENDJ_PASSWORD&quot; to &quot;*****&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;JDBC_CONNECTION_STRING&quot; to &quot;&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;JDBC_USERNAME&quot; to &quot;&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;JDBC_PASSWORD&quot; to &quot;*****&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;ACTION&quot; to &quot;3&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;Main_ACTION&quot; to &quot;3&quot; : Success
2025-08-08  6:38:40 Adding Pre-req &quot;TOMCAT7_HIGHER&quot;
...
2025-08-08  6:38:40 Action #1 ended: OK
2025-08-08  6:38:40 Setting environment variable &quot;PRIMARY_FQDN&quot; to &quot;otds-1.otds.otdsdev.svc.cluster.local&quot; : Success
2025-08-08  6:38:40 Setting environment variable &quot;ISREPLICA_TOPOLOGY&quot; to &quot;1&quot; : Success
2025-08-08  6:38:40 Skipping IMPORT_DATA parameter (condition is false)
2025-08-08  6:38:40 Skipping OTDS_PASS parameter (condition is false)
2025-08-08  6:38:40 Setting environment variable &quot;ENCRYPTION_KEY&quot; to &quot;mqLgucZ8UIUnNcLwjwmhNw==&quot; : Success
2025-08-08  6:38:40 Skipping MIGRATION_OPENDJ_URL parameter (condition is false)
2025-08-08  6:38:40 Skipping MIGRATION_OPENDJ_PASSWORD parameter (condition is false)
2025-08-08  6:38:40 Error, parameter JDBC_CONNECTION_STRING not defined.
2025-08-08  6:38:40 Setup Ended: 1
2025-08-08  6:38:40 ============= Verbose logging Ended =============
&#x5B;tomcat@otds-1 workspace_otds]$
</pre></div>


<p class="wp-block-paragraph">For reference, here is the content of the &#8220;silent.properties&#8221; file that this Replica installation uses:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [19,25,26]; title: ; notranslate">
&#x5B;tomcat@otds-1 workspace_otds]$ cat otds/silent.properties
&#x5B;Setup]
Id=OTDS
Version=24.4.0.4503
Patch=0
Basedir=/app/scripts/workspace_otds/otds
Configfile=/app/scripts/workspace_otds/otds/setup.xml
Action=Install
Log=/app/scripts/workspace_otds/otds/otds.log
Instance=1
Feature=All

&#x5B;Property]
INST_GROUP=tomcat
INST_USER=tomcat
INSTALL_DIR=/app/tomcat/app_data/otds
TOMCAT_DIR=/app/tomcat
PRIMARY_FQDN=otds-1.otds.otdsdev.svc.cluster.local
ISREPLICA_TOPOLOGY=1
IMPORT_DATA=0
OTDS_PASS=m1z6GX+HEX81DRpC
ENCRYPTION_KEY=mqLgucZ8UIUnNcLwjwmhNw==
MIGRATION_OPENDJ_URL=
MIGRATION_OPENDJ_PASSWORD=
JDBC_CONNECTION_STRING=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=db_host.domain.com)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=db_svc.domain.com)))
JDBC_USERNAME=OTDS
JDBC_PASSWORD=Shu#Asd#Tgb;6799
&#x5B;tomcat@otds-1 workspace_otds]$
</pre></div>


<p class="wp-block-paragraph">(These are the real passwords from that environment. I have changed them since then, obviously, but I included them so you can understand the details below. The encryption key is altered, though &#8211; the system originally took the real one from the &#8220;Primary&#8221; instance.)</p>



<h2 class="wp-block-heading" id="h-3-status-of-the-installer-created-managed-files">3. Status of the installer created/managed files</h2>



<p class="wp-block-paragraph">After the failure, I checked the parameter file that the OTDS installer populates during installation, but it was mostly empty and not yet filled:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [10,16,19,25,31,34]; title: ; notranslate">
&#x5B;tomcat@otds-1 workspace_otds]$ cat /etc/opentext/unixsetup/OTDS_parameters_1.txt

#GROUP name that should be used to change file group ownership (group of USER)
INST_GROUP=tomcat

#USER name that should be used to change file ownership (user running processes)
INST_USER=tomcat

#Specify the installation directory for OpenText Directory Services
INSTALL_DIR=/usr/local/OTDS

#Specify the directory, where (64-bit) Apache Tomcat 10 or higher is installed
TOMCAT_DIR=/app/tomcat

#This hostname is used by other instances to connect to the synchronization master host.
PRIMARY_FQDN=

#Is this server a supplementary instance to an existing environment?
ISREPLICA_TOPOLOGY=0

#Specify OpenDJ connection for import.
IMPORT_DATA=0

#Specify the data encryption key from an existing instance.
ENCRYPTION_KEY=

#OpenDJ LDAP URL (example: ldap://localhost:1389)
MIGRATION_OPENDJ_URL=

#Specify JDBC connection String (example: jdbc:postgresql://localhost:5432/postgres). NOTE: Enter these values carefully since they cannot be validated here. Refer to the OTDS installation and administration guide for JDBC URL samples for supported databases.
JDBC_CONNECTION_STRING=

#Specify Database User Name
JDBC_USERNAME=
&#x5B;tomcat@otds-1 workspace_otds]$
</pre></div>


<p class="wp-block-paragraph">Finally, the &#8220;<strong><em>otds.properties</em></strong>&#8221; file (normally generated during the installation) was also not present yet:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
&#x5B;tomcat@otds-1 workspace_otds]$ ls -l $APP_DATA/otds/config/otds.properties
ls: cannot access &#039;/app/tomcat/app_data/otds/config/otds.properties&#039;: No such file or directory
&#x5B;tomcat@otds-1 workspace_otds]$
</pre></div>


<h2 class="wp-block-heading" id="h-4-attempts-to-debug-the-issue">4. Attempts to debug the issue</h2>



<p class="wp-block-paragraph">I tried launching the installer multiple times, on that OTDS Replica, while making small changes to the silent properties file to see if something specific would cause it to fail. Starting by modifying the &#8220;<em><strong>JDBC_CONNECTION_STRING</strong></em>&#8221; parameter, since that is what the installer complained about, but without success. I then suspected the password parameter. Because passwords are masked in the logs (&#8220;<strong>*</strong>&#8220;), it is impossible to see whether the value is parsed correctly or not.</p>



<p class="wp-block-paragraph">Therefore, I replaced the OTDS Admin password in the silent properties file with &#8220;<em><strong>dummyPassword</strong></em>&#8220;, and the installer suddenly proceeded further&#8230; I cancelled the installation because this was not the real password of the &#8220;<em><strong>otadmin</strong></em>&#8221; account on the Primary instance, but in this case the &#8220;<em><strong>JDBC_CONNECTION_STRING</strong></em>&#8221; parameter was no longer empty and the installer continued normally.</p>



<p class="wp-block-paragraph"><em><strong>Note:</strong></em> the OTDS documentation specifies that passwords must contain at least eight characters, including one lowercase letter, one uppercase letter, one number, and one special character. However, it appears that this rule may not be strictly validated during Replica installations (and possibly not for the Primary either?).</p>



<p class="wp-block-paragraph">At that point it became clear that the password itself was involved in the issue, somehow. Looking at the script &#8220;<em><strong>tools/setup.sh</strong></em>&#8220;, you can see that the installer extracts the value of &#8220;<em><strong>OTDS_PASS</strong></em>&#8220;, applies a function called &#8220;<em><strong>AsctoHex</strong></em>&#8220;, and then encrypts it. My original &#8220;<em><strong>otadmin</strong></em>&#8221; password was 16 characters long and satisfied all complexity requirements. However, I noticed that the password contained the string &#8220;<em><strong>HEX</strong></em>&#8220;. Since the installer converts the password to hexadecimal before encryption, I wondered whether the presence of the string &#8220;<em><strong>HEX</strong></em>&#8221; might interfere with this process. That would be quite unbelievable, right?</p>



<h2 class="wp-block-heading" id="h-5-a-problem-with-the-password-length-or-content">5. A problem with the password length or content?</h2>



<p class="wp-block-paragraph">To test this idea, I removed the &#8220;<em><strong>E</strong></em>&#8221; in the middle, transforming &#8220;<em><strong>HEX</strong></em>&#8221; into &#8220;<em><strong>HX</strong></em>&#8221; and effectively reducing the password length by one character:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
&#x5B;tomcat@otds-1 workspace_otds]$ grep OTDS_PASS otds/silent.properties | awk -F= &#039;{print $2}&#039; | wc -c
17
&#x5B;tomcat@otds-1 workspace_otds]$ # 17 means 16 char since wc -c count the new line in this command
&#x5B;tomcat@otds-1 workspace_otds]$
&#x5B;tomcat@otds-1 workspace_otds]$ sed -i &#039;s,HEX,HX,&#039; otds/silent.properties
&#x5B;tomcat@otds-1 workspace_otds]$
&#x5B;tomcat@otds-1 workspace_otds]$ grep OTDS_PASS otds/silent.properties | awk -F= &#039;{print $2}&#039; | wc -c
16
&#x5B;tomcat@otds-1 workspace_otds]$ # 16 means 15 char now
</pre></div>


<p class="wp-block-paragraph">To re-execute the installer after a failure, you must remove the content of the &#8220;<em><strong>/etc/opentext</strong></em>&#8221; directory (which kind of caches the content from the &#8220;<em><strong>silent.properties</strong></em>&#8221; file) and also delete the &#8220;<em><strong>otds.properties</strong></em>&#8221; file if it exists (not in my case):</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
&#x5B;tomcat@otds-1 workspace_otds]$ rm -rf /etc/opentext/*
&#x5B;tomcat@otds-1 workspace_otds]$
</pre></div>


<p class="wp-block-paragraph">In addition to modifying the &#8220;<em><strong>silent.properties</strong></em>&#8221; file, I also changed the &#8220;<em><strong>otadmin</strong></em>&#8221; password through the OTDS otds-admin UI (see the OTDS Install &amp; Admin Guide, section 7.2.5 &#8220;Resetting a user password&#8221;). Then I started a new Replica installation to see whether changing &#8220;<em><strong>HEX</strong></em>&#8221; to &#8220;<em><strong>HX</strong></em>&#8221; from the password would resolve the issue:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
&#x5B;tomcat@otds-1 workspace_otds]$ /app/scripts/workspace_otds/otds/setup -qbi -rf /app/scripts/workspace_otds/otds/silent.properties

OpenText Directory Services 24.4.0

------------------------------------------------------------------------------
  OpenText Directory Services
------------------------------------------------------------------------------
Installing OpenText Directory Services Component
Please wait .
Installation of OpenText Directory Services Component OK

Installation completed. Results:

OpenText Directory Services Component OK

Installation finished.

&#x5B;tomcat@otds-1 workspace_otds]$
</pre></div>


<p class="wp-block-paragraph">… It worked …?</p>



<p class="wp-block-paragraph">If the issue was really caused by the presence of &#8220;<em><strong>HEX</strong></em>&#8221; in the password, then replacing it with &#8220;<em><strong>HXE</strong></em>&#8221; should also work, right? Unfortunately, when I tried that, the issue came back&#8230; This indicates that the real problem is not the literal &#8220;<em><strong>HEX</strong></em>&#8221; string but maybe something related to password length, complexity, or how the installer processes and encrypts the password internally?</p>



<h2 class="wp-block-heading" id="h-6-conclusion">6. Conclusion</h2>



<p class="wp-block-paragraph">In the end, I reverted to the shorter 15-character password that worked and prepared all higher environments at this customer to use 15-character passwords. This approach worked without issue for five additional environments until, of course, it failed again, in Production…</p>



<p class="wp-block-paragraph">Since it failed in another environment even with a 15-character password, the length alone does not seem to be the root cause. When reviewing previously installed environments across multiple customers, I found a few instances running with &#8220;<em><strong>otadmin</strong></em>&#8221; passwords of up to 19 characters long (about 111/120 bits of entropy according to a password manager like KeePass). This is significantly stronger than the 15-character password (96 bits) used in the Production environment where the issue occurred.</p>



<p class="wp-block-paragraph">Therefore, since I couldn&#8217;t find any logical reasons why the issue happened on some environments but not with others, I opened a ticket with OpenText. I described everything and we went through several weeks of exchanges to try to find an explanation but without success. As of today, I still don&#8217;t know why ~10% of the OTDS Replicas that I installed faced an issue with the OT Admin password, but the fix, was simply to change the password in the UI and start the silent installation again. I don&#8217;t have an environment to test / debug that issue anymore, since it&#8217;s not easily reproducible. Guess I will need to wait for next time to get more debug logs from the OTDS installer (&#8220;<em><strong>-debug</strong></em>&#8221; option). In the meantime, I can only assume something is probably wrong in the way OTDS manages the password or its hash.</p>



<p class="wp-block-paragraph"></p>
<p>L’article <a href="https://www.dbi-services.com/blog/otds-installation-of-replicas-fail-if-the-ot-admin-password-is-too-long/">OTDS &#8211; Installation of Replicas fail if the OT Admin password is too long?</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/otds-installation-of-replicas-fail-if-the-ot-admin-password-is-too-long/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Standardize SQL Server Disks on VMs using Ansible</title>
		<link>https://www.dbi-services.com/blog/how-to-standardize-sql-server-disks-on-vms-using-ansible/</link>
					<comments>https://www.dbi-services.com/blog/how-to-standardize-sql-server-disks-on-vms-using-ansible/#respond</comments>
		
		<dc:creator><![CDATA[Nathan Courtine]]></dc:creator>
		<pubDate>Mon, 23 Mar 2026 17:50:46 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Automation]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=43534</guid>

					<description><![CDATA[<p>INTRODUCTION Today, the benefits of automation no longer need much explanation: saving time, reducing human error, and ensuring every environment remains aligned with internal standards. What is less obvious, however, is how using an Ansible Playbook can provide advantages that more traditional scripting approaches — such as large PowerShell scripts — struggle to offer. That [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/how-to-standardize-sql-server-disks-on-vms-using-ansible/">How to Standardize SQL Server Disks on VMs using Ansible</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-introduction">INTRODUCTION</h2>



<p class="wp-block-paragraph">Today, the benefits of automation no longer need much explanation: saving time, reducing human error, and ensuring every environment remains aligned with internal standards. What is less obvious, however, is how using an Ansible Playbook can provide advantages that more traditional scripting approaches — such as large PowerShell scripts — struggle to offer. That is exactly what I want to explore here.</p>



<p class="wp-block-paragraph">When you complete an automated deployment of a SQL Server environment on Windows Server, there is a real sense of achievement. You have invested time and effort, and you expect that investment to pay off thanks to the reliability and repeatability of automation.</p>



<p class="wp-block-paragraph">But everything changes when the next Windows Server upgrade or SQL Server version arrives… or when corporate standards evolve. Suddenly, you need to reopen a multi-thousand‑line PowerShell script and:</p>



<ul class="wp-block-list">
<li>Integrate the required changes while keeping execution stable,</li>



<li>Avoid subtle but potentially critical regressions,</li>



<li>Maintain clear and usable logging,</li>



<li>Retest the entire automation workflow,</li>



<li>Troubleshoot new issues introduced by the modifications.</li>
</ul>



<p class="wp-block-paragraph">This is precisely the type of situation where Ansible becomes a far better long‑term investment. Its architecture and philosophy offer several advantages:</p>



<ul class="wp-block-list">
<li>Native idempotence, ensuring the same result even after multiple runs,</li>



<li>A declarative YAML approach, focusing on the desired end state rather than the execution steps,</li>



<li>Windows Server and SQL Server modules, providing built‑in idempotence and saving significant time,</li>



<li>Agentless connectivity, simplifying deployment on new machines,</li>



<li>A modular structure (roles, modules, variables), making adaptation and reuse of your automation much easier.</li>
</ul>



<p class="wp-block-paragraph">In this article, I will give you a concrete overview by walking you through how to configure the disks required for SQL Server using Ansible.</p>



<h2 class="wp-block-heading" id="h-1-map-iscsi-controllers-to-disk-numbers">1-Map iSCSI controllers to disk numbers</h2>



<p class="wp-block-paragraph">When developing an Ansible Playbook, one fundamental principle is to design for idempotence from the very start—not just rely on idempotent modules.</p>



<p class="wp-block-paragraph">On Windows, disk numbering is not guaranteed: it depends on several factors – how disks are detected at startup, the firmware, and so on.<br>As a result, disk numbers may change from one reboot to another.</p>



<p class="wp-block-paragraph">To ensure consistent and reliable execution of your deployment, this behavior must be accounted for directly in the design of your Playbook.<br>Otherwise, it may introduce wrong behaviors, and lead to:</p>



<ul class="wp-block-list">
<li>formatting the wrong disk,</li>



<li>mounting volumes on incorrect devices,</li>



<li>completely breaking the SQL Server provisioning workflow.</li>
</ul>



<p class="wp-block-paragraph">In other words, idempotence is no longer guaranteed.</p>



<p class="wp-block-paragraph">To ensure stable and predictable executions, you must determine dynamically the correct disk numbering at each execution.<br></p>



<p class="wp-block-paragraph">You can use Get-Disk PowerShell command to achieve your goal, by searching iSCSI controller number and LUN position from Location property.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; gutter: false; title: ; notranslate">
$adapter = {{ disk.adapter }}
$lun = {{ disk.lun}}
(Get-Disk | Where-Object {
      $_.Location -match &quot;Adapter $adapter\s+:.*\s+LUN $lun&quot;
    }).number
</pre></div>


<p class="wp-block-paragraph">We have done our mapping between VM specifications and Windows disk numbers.</p>



<h2 class="wp-block-heading" id="h-2-loop-sql-server-disks">2-Loop SQL Server disks</h2>



<p class="wp-block-paragraph">Since we often have several disks to configure — Data, Logs, TempDB — we need to perform the same actions repeatedly on each disk:</p>



<ul class="wp-block-list">
<li>dynamically determine the disk number,</li>



<li>initialize it in GPT,</li>



<li>create the partition and format the volume in NTFS with a 64 KB allocation unit size,</li>



<li>assign an access path (drive letter or mountpoint),</li>



<li>apply certain specific configuration settings, such as disabling indexing,</li>



<li>verify the compliance of the disk configuration.</li>
</ul>



<p class="wp-block-paragraph">As these actions are identical for all disks, the best approach is to factorize the tasks.<br>The Ansible pattern, for such scenario, is to loop that call in a dedicated Task File.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
---

- name: Manage all disk properties based on Location and Target numbers
  ansible.builtin.include_tasks: disks_properties.yml
  loop:
    - name: data
      location: &quot;{{ disk_specs.data.location }}&quot;
      target: &quot;{{ disk_specs.data.target }}&quot;
      label: &quot;{{ disk_specs.data.label }}&quot;
      letter: &quot;{{ disk_specs.data.letter }}&quot;
    - name: logs
      location: &quot;{{ disk_specs.logs.location }}&quot;
      target: &quot;{{ disk_specs.logs.target }}&quot;
      label: &quot;{{ disk_specs.logs.label }}&quot;
      letter: &quot;{{ disk_specs.logs.letter }}&quot;
    - name: tempdb
      location: &quot;{{ disk_specs.tempdb.location }}&quot;
      target: &quot;{{ disk_specs.tempdb.target }}&quot;
      label: &quot;{{ disk_specs.tempdb.label }}&quot;
      letter: &quot;{{ disk_specs.tempdb.letter }}&quot;
  loop_control:
    loop_var: disk

...
</pre></div>


<h2 class="wp-block-heading" id="h-3-implement-sql-server-disk-configuration">3- Implement SQL Server disk configuration</h2>



<p class="wp-block-paragraph">Since we performed our loop in the previous section on the disks_properties.yml file, we can now implement the configuration actions inside this file.<br>First, we will retrieve the disk number and then begin configuring the disk according to best practices and our internal standards.</p>



<p class="wp-block-paragraph">To guarantee idempotence, we will mark this step as not changed: this is only a Get action:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
---

- name: Identify the {{ disk.name }} disk number
  ansible.windows.win_shell: |
    $adapter = {{ disk.target }}
    $lun = {{ disk.location }}
    (Get-Disk | Where-Object {
      $_.Location -match &quot;Adapter $adapter\s+:.*\s+LUN $lun&quot;
    }).number
  register: disk_num
  changed_when: false
</pre></div>


<p class="wp-block-paragraph">Then, we will register the disk number as an Ansible Fact for all this task file execution call.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
- name: Set fact for {{ disk.name }} disk number
  ansible.builtin.set_fact:
    &quot;disk_number_{{ disk.name }}&quot;: &quot;{{ disk_num.stdout | trim | int }}&quot;
</pre></div>


<p class="wp-block-paragraph">We can now initialize the disk using <em>community.windows</em> module. Of course, use Ansible module if possible.</p>



<p class="wp-block-paragraph">The parameter <em>disk_bps.partition_style</em> is a variable of my Ansible Role, to guarantee GPT will be used.<br></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
- name: Initialize disks
  community.windows.win_initialize_disk:
    disk_number: &quot;{{ lookup(&#039;vars&#039;, &#039;disk_number_&#039; + disk.name) }}&quot;
    style: &quot;{{ disk_bps.partition_style }}&quot;
</pre></div>


<p class="wp-block-paragraph">From there, we can create our partition: </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
- name: Create partition with letter {{ disk.letter }} for disk {{ disk.name }}
  community.windows.win_partition:
    drive_letter: &quot;{{ disk.letter }}&quot;
    partition_size: &quot;-1&quot;
    disk_number: &quot;{{ lookup(&#039;vars&#039;, &#039;disk_number_&#039; + disk.name) }}&quot;
</pre></div>


<p class="wp-block-paragraph">And now format our volume with allocation unit size 64KB:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
- name: Create a partition letter {{ disk.letter }} on disk {{ disk.name }} with label {{ disk.label }}
  community.windows.win_format:
    drive_letter: &quot;{{ disk.letter }}&quot;
    allocation_unit_size: &quot;{{ disk_bps.allocation_unit_size_bytes }}&quot;
    new_label: &quot;{{ disk.label }}&quot;

...
</pre></div>


<p class="wp-block-paragraph">As I mentioned earlier in previous section, we can also add tasks relative to some specific standards or a tasks to guarantee disk compliance.</p>



<h2 class="wp-block-heading" id="h-4-execute-the-playbook">4- Execute the Playbook</h2>



<p class="wp-block-paragraph">Now that our Ansible Role <em>windows_disks</em> is ready, we can call it through a Playbook.<br>Of course, we must adjust the reality of the iSCSI configuration of the Virtual Machine.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
---

- name: Configure Disks by detecting Disk Number
  hosts: Raynor
  gather_facts: false
  vars:
    disk_specs:
      data:
        location: 0
        target: 1
        label: SQL_DATA
        letter: E
      logs:
        location: 0
        target: 2
        label: SQL_TLOG
        letter: L
      tempdb:
        location: 0
        target: 3
        label: SQL_TEMPDB
        letter: T
  tasks:
    - name: gather facts
      ansible.builtin.setup:
      changed_when: false
      tags: &#x5B;always]
    - name: Configure Disks
      ansible.builtin.import_role:
        name: windows_disks
      tags: windows_disks


...
</pre></div>


<figure data-wp-context="{&quot;imageId&quot;:&quot;6a3b19f6d2716&quot;}" data-wp-interactive="core/image" data-wp-key="6a3b19f6d2716" class="wp-block-image size-large wp-lightbox-container"><img decoding="async" width="1024" height="623" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/03/Ansible_disks-1024x623.png" alt="" class="wp-image-43551" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/03/Ansible_disks-1024x623.png 1024w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/03/Ansible_disks-300x182.png 300w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/03/Ansible_disks-768x467.png 768w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2026/03/Ansible_disks.png 1329w" sizes="(max-width: 1024px) 100vw, 1024px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<h2 class="wp-block-heading" id="h-conclusion">CONCLUSION</h2>



<p class="wp-block-paragraph">We have had an overview of how Ansible makes automation easier to maintain and to evolve, by focusing on the logic of our deployment and not on the code to achieve it.<br>Now, updating your standards or upgrading versions will no longer require rewriting scripts, but mainly adapting variables.</p>



<p class="wp-block-paragraph">However, it is important to be aware that idempotence must also be maintained through design.<br></p>
<p>L’article <a href="https://www.dbi-services.com/blog/how-to-standardize-sql-server-disks-on-vms-using-ansible/">How to Standardize SQL Server Disks on VMs using Ansible</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/how-to-standardize-sql-server-disks-on-vms-using-ansible/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Automate encryption-in-transit for SQL Server</title>
		<link>https://www.dbi-services.com/blog/automate-encryption-in-transit-for-sql-server/</link>
					<comments>https://www.dbi-services.com/blog/automate-encryption-in-transit-for-sql-server/#respond</comments>
		
		<dc:creator><![CDATA[Nathan Courtine]]></dc:creator>
		<pubDate>Thu, 12 Feb 2026 12:31:22 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Security]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=42851</guid>

					<description><![CDATA[<p>Encryption-in-transit is part of the essential security baseline for SQL Server.Without TLS, TDS packets travel in clear text across the network, making them vulnerable to interception or modification by an attacker attempting to gain access to the system.This is why TLS has become a standard in modern SQL Server architectures. In this article, we will [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/automate-encryption-in-transit-for-sql-server/">Automate encryption-in-transit for SQL Server</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Encryption-in-transit is part of the essential security baseline for SQL Server.<br>Without TLS, TDS packets travel in clear text across the network, making them vulnerable to interception or modification by an attacker attempting to gain access to the system.<br>This is why TLS has become a standard in modern SQL Server architectures.</p>



<p class="wp-block-paragraph"><br>In this article, we will look at how to standardize and automate this deployment using PowerShell.<br>This will provide the core of the TLS setup, based on a certificate name and an instance name.<br>For full generalization, it only requires to loop over a list of instances, or to integrate it into an Ansible playbook, for example.</p>



<p class="wp-block-paragraph">In our automation, we assume that the certificate is already present in <code>Cert:\LocalMachine\My</code> (Local Machine Personal). The certificate is <strong>ws202201.dbi.test</strong> in this output:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; gutter: false; title: ; notranslate">
PS&gt; ls cert:\LocalMachine\My


   PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\My

Thumbprint                                Subject
----------                                -------
E6DB2D082B41B36F08806EA82B25064150618E1F  CN=CLIUSR
D4EBB1260BECFD28254082A734FD4D5663199B16  CN=CLIUSR
30B20A2A54A3DAB60E6AC601B94F6E5A626D7C2D  CN=ws202201.dbi.test
</pre></div>


<p class="wp-block-paragraph">The first step is to give the SQL Server service account read permissions on the certificate’s private key, otherwise the instance will not be able to use the certificate for TLS.<br>The script uses two input parameters : <strong>Instance Name</strong> of SQL Server and <strong>Friendly Name</strong> of the certificate.<br></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; gutter: false; title: ; notranslate">
#---- Variables -------------------------------------------------------------
$InstanceName = &#039;INSTANCE1&#039;;     # Instance name to adapt
$FriendlyName = &#039;Instance1 TLS&#039;; # Certificate Friendly Name to adapt

#---- Begin Script ----------------------------------------------------------
# Construct Virtual Account for SQL Server instance
If ($InstanceName -eq &#039;MSSQLSERVER&#039;) {
    $user = &#039;NT SERVICE\MSSQLSERVER&#039;;
} else {
    $user = &quot;NT SERVICE\$(&#039;MSSQL$&#039;+$InstanceName)&quot;;
};

# Retrieve certificate based on Friendly Name
$cert = Get-ChildItem -Path &#039;Cert:\LocalMachine\My&#039; ` 
| Where-Object {$_.FriendlyName -eq &quot;$FriendlyName&quot;};

# Give Virtual Account read permission
$permission = &quot;Read&quot;; 
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($user, $permission, &quot;Allow&quot;); 
$keyPath = &#x5B;System.IO.Path]::Combine(&quot;C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys&quot;, $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName); 
$acl = Get-Acl -Path $keyPath;
$acl.SetAccessRule($rule); 
Set-Acl -Path $keyPath -AclObject $acl;
</pre></div>


<p class="wp-block-paragraph">The next step is to reference the certificate’s thumbprint in the SQL Server registry configuration.<br>A key detail here: while PowerShell is <strong>case-insensitive</strong>, the thumbprint stored in the registry is <strong>case-sensitive</strong>. SQL Server expects the value to be written in lowercase; otherwise, the instance will not load the certificate at startup.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; gutter: false; title: ; notranslate">
# Root registry entry of instance (Regex)
$Pattern = &quot;MSSQL\d\d\.$($InstanceName)&quot;;

# Construct path where is stored Certificate property
$RegMSSQL = &#039;HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\&#039;;
$RegRootInstance = Get-childItem -Path $RegMSSQL `
| Where-Object Name -match &quot;$Pattern&quot;;

# Update Certificate property with certificate thrumprint in lower case
$RegTCPCertificate = &#039;MSSQLServer\SuperSocketNetLib\&#039;;
Set-ItemProperty ` 
-Path (Join-Path -Path $RegRootInstance.PSPath -ChildPath $RegTCPCertificate) `
-Name &#039;Certificate&#039; -Value &quot;$($cert.Thumbprint.ToLower())&quot;;
</pre></div>


<p class="wp-block-paragraph">All that remains is to restart the SQL Server service to apply the changes.</p>



<p class="wp-block-paragraph">To confirm encryption, connect SQL Server and run the following T-SQL command:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; gutter: false; title: ; notranslate">
SELECT 
  session_id 
  ,encrypt_option
FROM sys.dm_exec_connections 
WHERE session_id = @@SPID


session_id encrypt_option
---------- --------------
        60 TRUE
</pre></div>


<p class="wp-block-paragraph"></p>
<p>L’article <a href="https://www.dbi-services.com/blog/automate-encryption-in-transit-for-sql-server/">Automate encryption-in-transit for SQL Server</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/automate-encryption-in-transit-for-sql-server/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>pgconf.eu 2025 &#8211; RECAP</title>
		<link>https://www.dbi-services.com/blog/pgconf-eu-2025-recap/</link>
					<comments>https://www.dbi-services.com/blog/pgconf-eu-2025-recap/#respond</comments>
		
		<dc:creator><![CDATA[Adrien Obernesser]]></dc:creator>
		<pubDate>Sun, 26 Oct 2025 18:30:40 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[pgconfeu]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=41244</guid>

					<description><![CDATA[<p>I was fortunate to be able to attend at the pgconf.eu 2025. This year event was happening in RIGA and joined together once again key members of the community, contributors, committers, sponsors and users from across the world. I would summarize this year event with those three main topics : AI/LLM &#8211; PG18- Monitoring. AI/LLMs [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/pgconf-eu-2025-recap/">pgconf.eu 2025 &#8211; RECAP</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-group is-vertical is-content-justification-center is-layout-flex wp-container-core-group-is-layout-524f8de7 wp-block-group-is-layout-flex">
<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="1024" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/95801-1-1024x1024.jpg" alt="" class="wp-image-41250" style="width:575px;height:auto" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/95801-1-1024x1024.jpg 1024w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/95801-1-300x300.jpg 300w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/95801-1-150x150.jpg 150w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/95801-1-768x768.jpg 768w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/95801-1-1536x1536.jpg 1536w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/95801-1.jpg 1716w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">I was fortunate to be able to attend at the <a href="https://2025.pgconf.eu/">pgconf.eu 2025</a>. <br>This year event was happening in RIGA and joined together once again key members of the community, contributors, committers, sponsors and users from across the world. <br>I would summarize this year event with those three main topics : AI/LLM &#8211; PG18- Monitoring. </p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading" id="h-ai-llms">AI/LLMs</h2>



<p class="wp-block-paragraph"><br>Compared to last year the formula changed a bit regarding the Community events day of Tuesday where for the first time different &#8220;Summits&#8221; where organized. If you want full details on the event and the schedule as well as the presentation slides of each talk you may find it here : <a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/">Schedule — PostgreSQL Conference Europe 2025</a><br>I had the chance to be chosen as a speaker for the AI Summit. It was quite interesting for me. In total there was 13 short talks (10min) on various topics related to PostgreSQL and AI/LLMs it was dense with a lot of interesting ideas of implementations &#8211; you can find the details and slides here <a href="https://wiki.postgresql.org/wiki/PGConf.EU_2025_PostgreSQL_AI_Summit">PGConf.EU 2025 PostgreSQL AI Summit &#8211; PostgreSQL wiki</a>. AI/LLMs are the hot topic of the moment and naturally it came up often during this event, in the talks and in the discussions. You can find the pdf of my presentation <a href="https://drive.google.com/file/d/1qrE-42-CFVvIJ4PZ1dvkTuAVPWUkNSwF/view?pli=1">here</a>. I explained a business case implementation of a BI self-service agentic RAG to find relevant fields for a target KPI and data marts creation as output. Since the talks were short, it allowed to have a debate at the end between the audience and the speakers. The discussion nicely moderated by organizers was interesting because it exposed the same strong thoughts people have in general about AI/LLMs. A blend of distrust and not fully understanding of what it is about or how it could help organizations. Which, in itself, shows that the PostgreSQL community has the same difficulties at explaining technical challenges versus organizational/human challenges. My view here is that we don&#8217;t have technical challenges, they are almost un-relevant to most arguments but rather human relation and understanding of what values a DBA for example, brings to the organization. To me installing and configuring PostgreSQL has no benefits in terms of personal growth so automating it is quite natural and adding AI/LLMs on top is &#8220;nice to have&#8221; but not fundamentally different than an Ansible playbook. But for the junior DBA this an additional abstraction that can be dangerous because it provides tools that users can&#8217;t grasp the full extent of their consequences.  This outlines that the main issue of integrating AI/LLMs workflows is more a governance/ C-management issue than a technical one and it can&#8217;t be the last excuse for adding to the technological debt. <br><a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/session/6932-dont-leak-user-data-to-ai-strategies-for-protecting-pii-from-llms-and-mcp/">Jay Miller</a> from Aiven explained how you can fail at exposing PII from LLMs and MCPs. This is rely a relevant topic knowing that more and more organization are facing issues like shadow IT. He also was quite the show host and was funny to hear. I recommend strongly watching the recording when it will be released. </p>
</div>



<h2 class="wp-block-heading has-text-align-center" id="h-pg18">PG18</h2>



<div class="wp-block-group is-vertical is-content-justification-center is-layout-flex wp-container-core-group-is-layout-524f8de7 wp-block-group-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="439" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9642-1024x439.jpg" alt="" class="wp-image-41247" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9642-1024x439.jpg 1024w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9642-300x129.jpg 300w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9642-768x329.jpg 768w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9642-1536x659.jpg 1536w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9642-2048x879.jpg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>



<p class="wp-block-paragraph">This year was just after the PostgreSQL 18 version release which is one the version that brought major improvements and is initiating changes for future release to come. I was quite enthusiast to listen to <a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/session/6952-improved-freezing-in-postgres-vacuum-from-idea-to-commit/">Melanie Plagemen</a> on how she worked on the improvements on freezing in this release. I have to say, usually when I am going at an advanced internal talk, I am more confused after than before. But here, Melanie did an amazing job at talking about a technical complex topic without loosing the audience. <br><a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/session/7133-what-you-should-know-about-constraints-in-postgresql-and-whats-new-in-18/">Gülçin Yıldırım Jelínek</a>, on her side explained what&#8217;s new in PG18 about constraints like NOT ENFORCED and NOT NULL and how to use them. The COO of Cybertec Raj Verma, during <a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/session/7185-from-chaos-to-compliance-how-postgresql-makes-regulations-work-for-you/">a sponsor talk</a>, explained why compliance matters and how to minimize the risks and how PostgreSQL is helping us to be PCI DSS, GDPR, nLPD or HIPAA compliant. <br> Another interesting talk I was happy to attend was from <a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/session/7021-they-grow-up-so-fast-donating-your-open-source-project-to-a-foundation/">Floor Drees and Gabriele Bartolini</a>. they explain how they went on joining the <a href="https://cloudnative-pg.io/">CloudNativePG</a> project to the CNCF.</p>



<p class="wp-block-paragraph"> </p>



<h2 class="wp-block-heading has-text-align-center" id="h-monitoring">Monitoring</h2>



<p class="wp-block-paragraph">This leads me to another important topic, I wasn&#8217;t looking for it but became a bit of a main subject for my over the years as a DBA that was interested in performance tuning. Monitoring on PostgreSQL was introduced by several talks like <a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/session/7187-dbtune-ai-driven-performance-tuning-for-all-postgresql-flavors/">Luigi Nardi</a> and his idea of workload fingerprint with the DBtune tool they have. Additionally,  <a href="https://www.postgresql.eu/events/pgconfeu2025/schedule/session/7112-tracking-plan-shapes-over-time-with-plan-ids-and-the-new-pg_stat_plans/">Lukas Fittl</a> presented pg_stat_plans, an extension which aims at tracking execution plans over time. This is definitely something I am going to try and will push for implementation in the core extensions if not the core code itself. <br>The reason for that is obvious for me, PostgreSQL is becoming more and more central to enterprise organizations and appart from subject like TDE, monitoring is going to become a key aspect of automation, CloudNativePG and AI/LLM workflows. Having PostgreSQL being able to be monitored better and easier at the core will allow leveraging at all this levels.  Cloud companies release that already hence there involvement in similar projects. <br><br>In the end, this year was once again the occasion for me to think about many relevant topics and exchange with PostgreSQL hackers as well as users from around the world. I came back home with the head full of ideas to investigate. </p>



<p class="wp-block-paragraph">Additionally after the conference the videos of the each talks will be uploaded to the pgconf Europe Youtube channel : <a href="https://www.youtube.com/@pgeu/videos">PostgreSQL Europe</a>, but you can already check previous amazing talks and this year pgday Paris.</p>



<p class="wp-block-paragraph">So once again the PostgreSQL flag was floating up high ! </p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="924" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9680-1024x924.jpg" alt="" class="wp-image-41248" style="width:726px;height:auto" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9680-1024x924.jpg 1024w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9680-300x271.jpg 300w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9680-768x693.jpg 768w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/9680.jpg 1280w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div><p>L’article <a href="https://www.dbi-services.com/blog/pgconf-eu-2025-recap/">pgconf.eu 2025 &#8211; RECAP</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/pgconf-eu-2025-recap/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>From JBoss EAP 7 to 8: What Really Changed</title>
		<link>https://www.dbi-services.com/blog/from-jboss-eap-7-to-8-what-really-changed/</link>
					<comments>https://www.dbi-services.com/blog/from-jboss-eap-7-to-8-what-really-changed/#respond</comments>
		
		<dc:creator><![CDATA[David Diab]]></dc:creator>
		<pubDate>Mon, 06 Oct 2025 12:44:12 +0000</pubDate>
				<category><![CDATA[Application integration & Middleware]]></category>
		<category><![CDATA[JBoss EAP]]></category>
		<category><![CDATA[migration]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=40762</guid>

					<description><![CDATA[<p>The arrival of JBoss EAP 8 marks a significant milestone in the evolution of Red Hat’s Enterprise Application Server. For many organizations still running on JBoss EAP 7.x, the upgrade brings not only new features but also strategic changes aligned with the modernization of the Java ecosystem.Let’s explore what really changed and what you need [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/from-jboss-eap-7-to-8-what-really-changed/">From JBoss EAP 7 to 8: What Really Changed</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The arrival of JBoss EAP 8 marks a significant milestone in the evolution of Red Hat’s Enterprise Application Server. For many organizations still running on JBoss EAP 7.x, the upgrade brings not only new features but also strategic changes aligned with the modernization of the Java ecosystem.<br>Let’s explore what really changed and what you need to know before moving forward.</p>



<span id="more-40762"></span>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1225" height="817" src="http://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/Jboss-7-to-8-4.png" alt="" class="wp-image-40772" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/Jboss-7-to-8-4.png 1225w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/10/Jboss-7-to-8-4-300x200.png 300w" sizes="auto, (max-width: 1225px) 100vw, 1225px" /></figure>



<h2 class="wp-block-heading" id="h-a-shift-toward-jakarta-ee">A Shift Toward Jakarta EE</h2>



<p class="wp-block-paragraph">The most visible and impactful change in JBoss EAP 8 is the transition from Java EE to Jakarta EE.</p>



<ul class="wp-block-list">
<li>Namespace migration: All javax.* packages are now replaced by jakarta.*.</li>



<li>This means that even if your application compiles fine on EAP 7, it won’t deploy on EAP 8 without updating imports and dependencies.</li>



<li>While this migration can sound painful, it’s a necessary step to stay compatible with the modern Java ecosystem and future versions of Jakarta EE.</li>
</ul>



<p class="wp-block-paragraph">We can count on the Red Hat’s EAP Migration Toolkit to automatically detect and fix most of the package name changes.</p>



<h2 class="wp-block-heading" id="h-new-java-and-platform-support">New Java and Platform Support</h2>



<p class="wp-block-paragraph">JBoss EAP 8 officially supports Java 17 and later.<br>This brings performance, security, and syntax improvements, while dropping support for older Java versions (like Java 8 in many cases).</p>



<p class="wp-block-paragraph">Other platform updates include:</p>



<ul class="wp-block-list">
<li>Updated Undertow web server version for improved HTTP/2 and security.</li>



<li>Enhanced datasource and driver management via the CLI and management console.</li>



<li>Simplified configuration through YAML and CLI scripts, helping automate deployments and tuning.</li>
</ul>



<h2 class="wp-block-heading" id="h-updated-subsystems-and-architecture-improvements">Updated Subsystems and Architecture Improvements</h2>



<p class="wp-block-paragraph">EAP 8 brings a more modular, streamlined architecture:</p>



<ul class="wp-block-list">
<li>Legacy subsystems deprecated (e.g., older messaging or logging frameworks).</li>



<li>MicroProfile updates: More APIs for observability, configuration, and fault tolerance.</li>



<li>Improved clustering and domain mode management, faster startup and better node synchronization.</li>
</ul>



<p class="wp-block-paragraph">For administrators, these changes mean fewer manual tweaks and more consistent runtime behavior across environments.</p>



<h2 class="wp-block-heading" id="h-ready-for-the-cloud-for-real">Ready for the Cloud (for Real <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> )</h2>



<p class="wp-block-paragraph">Red Hat has made significant investments to make EAP 8 cloud-native:</p>



<ul class="wp-block-list">
<li>Better support for OpenShift and Kubernetes with optimized container images.</li>



<li>Smaller footprint and faster startup thanks to tuned modules and lazy loading.</li>



<li>Compatibility with Red Hat build of Quarkus for microservice migration paths.</li>
</ul>



<p class="wp-block-paragraph">In other words, JBoss EAP 8 is no longer just a traditional application server, it’s a hybrid platform that bridges the gap between legacy Java EE workloads and modern cloud architectures.</p>



<h2 class="wp-block-heading" id="h-security-and-compliance-enhancements">Security and Compliance Enhancements</h2>



<p class="wp-block-paragraph">Security was a major focus in JBoss EAP 8:</p>



<ul class="wp-block-list">
<li>Integrated Elytron 2 for modern authentication and authorization.</li>



<li>Stronger TLS configurations by default.</li>



<li>Simplified credential store management (replacing legacy vault mechanisms).</li>
</ul>



<p class="wp-block-paragraph">Administrators will appreciate the more centralized, policy-driven security model.</p>



<h2 class="wp-block-heading" id="h-my-experience-amp-recommendations">My Experience &amp; Recommendations</h2>



<p class="wp-block-paragraph">After long time working with both JBoss EAP 7 and JBoss EAP 8, I can say the migration is more about preparation than complexity.<br>The most common pitfalls I’ve seen include:</p>



<ul class="wp-block-list">
<li>Forgetting the Jakarta namespace migration.</li>



<li>Using old JDBC drivers or libraries no longer supported.</li>



<li>Missing dependencies when running in containerized environments.</li>
</ul>



<p class="wp-block-paragraph">Our best practice is always to:</p>



<ul class="wp-block-list">
<li>Test the migration in a clean environment.</li>



<li>Use automation (Ansible or CI/CD pipelines) for consistent builds.</li>



<li>Validate performance, logging, and metrics integration (especially with Zabbix or Elastic).</li>
</ul>



<p class="wp-block-paragraph">Once properly prepared, JBoss EAP 8 runs smoother, faster, and integrates much better with modern infrastructure.</p>



<h2 class="wp-block-heading" id="h-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JBoss EAP 8 isn’t just an upgrade, it’s a modernization step.<br>It pushes Java EE into the Jakarta EE era, embraces cloud-native deployments, and simplifies operations for enterprises.<br>While the migration from EAP 7 requires careful planning, the long-term benefits in performance, maintainability, and compliance make it well worth the effort.</p>



<p class="wp-block-paragraph">If you’re planning a JBoss migration, feel free to reach out for guidance or a technical exchange.<br>Have a look at our <a href="https://www.dbi-services.com/blog/tag/jboss/" target="_blank" rel="noreferrer noopener">JBoss EAP blogs</a> for more insights.</p>



<p class="wp-block-paragraph">Happy to share,</p>



<p class="wp-block-paragraph">David</p>
<p>L’article <a href="https://www.dbi-services.com/blog/from-jboss-eap-7-to-8-what-really-changed/">From JBoss EAP 7 to 8: What Really Changed</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/from-jboss-eap-7-to-8-what-really-changed/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Errorhandling in Ansible</title>
		<link>https://www.dbi-services.com/blog/errorhandling-in-ansible/</link>
					<comments>https://www.dbi-services.com/blog/errorhandling-in-ansible/#respond</comments>
		
		<dc:creator><![CDATA[Martin Bracher]]></dc:creator>
		<pubDate>Thu, 18 Sep 2025 13:54:32 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[errorhandling]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=39033</guid>

					<description><![CDATA[<p>Errors in tasks &#8211; abort or ignore? Per default, if a task in a playbook fails, then the execution of the playbook is stopped for that host. As you can see, the 2nd task is not executed. If you want to continue in such a case, the ignore_errors parameter is your friend Custom error conditions [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/errorhandling-in-ansible/">Errorhandling in Ansible</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-errors-in-tasks-abort-or-ignore">Errors in tasks &#8211; abort or ignore?</h2>



<p class="wp-block-paragraph">Per default, if a task in a playbook fails, then the execution of the playbook is stopped for that host. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
- name: PLAY1
  hosts: localhost
  gather_facts: no
  tasks:
    - name: let this shell-command fail
      ansible.builtin.shell: exit 1

    - name: let this shell-command complete
      ansible.builtin.shell: exit 0
</pre></div>


<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="847" height="142" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/06/image-1.png" alt="" class="wp-image-39042" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/06/image-1.png 847w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/06/image-1-300x50.png 300w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/06/image-1-768x129.png 768w" sizes="auto, (max-width: 847px) 100vw, 847px" /></figure>



<p class="wp-block-paragraph">As you can see, the 2nd task is not executed. If you want to continue in such a case, the <code>ignore_errors</code> parameter is your friend</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
    - name: let this shell-command fail
      ansible.builtin.shell: exit 1
      ignore_errors: true
</pre></div>


<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="847" height="170" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/06/image-2.png" alt="" class="wp-image-39043" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/06/image-2.png 847w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/06/image-2-300x60.png 300w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/06/image-2-768x154.png 768w" sizes="auto, (max-width: 847px) 100vw, 847px" /></figure>



<h2 class="wp-block-heading" id="h-custom-error-conditions">Custom error conditions</h2>



<p class="wp-block-paragraph">Per default, Ansible evaluates the exit-code of the module, in case of the shell-module, the exit-code of the last command.</p>



<p class="wp-block-paragraph">But for some commands, that is not adequate. Example: The Oracle commandline tool <code>sqlplus</code> to submit sql-commands will have an exit-code of 0 if it can connect to the database-instance. It is not related to the result of your SQL-commands. Error-messages in Oracle are prefixed by ORA-.</p>



<p class="wp-block-paragraph">So, if you want to check for application errors, you have to implement it yourself. For that, you can use the <code>failed_when</code> option.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
    - name: let this shell-command fail
      ansible.builtin.shell: |
        . ~/.profile
        echo &quot;select count(*) from all_users;&quot; | sqlplus / as sysdba
      register: number_of_users
      failed_when: &quot;&#039;ORA-&#039; in number_of_users.stdout&quot;
</pre></div>


<p class="wp-block-paragraph">Caution: In this case the exit-code of the shell is no longer evaluated. To also get the exit-code of the sqlplus call (e.g., sqlplus can not connect to the database, or sqlplus binary not found), you have to add this (default) condition: </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
      failed_when: &quot;number_of_users.rc != 0 or &#039;ORA-&#039; in number_of_users.stdout&quot;
</pre></div>


<p class="wp-block-paragraph">But caution! Not all modules will have an <code>rc</code> field.</p>



<h2 class="wp-block-heading" id="h-tuning-perform-several-checks-at-once">Tuning: Perform several checks at once</h2>



<p class="wp-block-paragraph">Conceptually, Ansible is not the fastest tool. For each task, it will usually login with ssh to the remote server. If you have to run several checks in the shell, then, instead of running each in a separate task, you can run all these check-commands in one shell-task, and evaluate the result afterwards.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
    - name: run many check commands
      ansible.builtin.shell: |
        mount | grep &#039; on /u00 &#039;  #check if /u00 is mounted
        rpm -q ksh 2&gt;&amp;1  #check if ksh is installed
        exit 0 # do not fail if rpm exit != 0; we will do our own errorhandling
      register: checks

    - name: fail if no /u00 is mounted
      fail:
        msg: &quot;/u00 is not mounted&quot;
      when: &quot;&#039; on /u00 &#039; not in checks.stdout&quot;

    - name: No ksh found, try to install it
      yum:
        name: ksh
        state: present
      when: &quot;&#039;package ksh is not installed&#039; in checks.stdout&quot;

</pre></div>


<p class="wp-block-paragraph">If you only want to throw an error, then you can do it directly in the shell-task:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
when: &quot;&#039; on /u00 &#039; not in checks.stdout&quot; or &#039;package ksh is not installed&#039; in checks.stdout
</pre></div>


<p class="wp-block-paragraph"> But if you parse the output afterwards, you can run tasks to fix the error. </p>



<p class="wp-block-paragraph">Sometimes it is difficult to parse the output if some commands return the same output, e.g. &#8220;OK&#8221;.<br>If your check-commands always return exactly 1 line, then you can directly parse the output of the command. The output of the 3rd command is in <code>checks.stdout_lines[2]</code>.<br>In the above example that will not work because <code>grep</code> will return the exit-code 0 (not found) or 1 (found) plus the found line. So, expand it as: <code>mount | grep ' on /u00 ' || echo error</code></p>



<h2 class="wp-block-heading" id="h-print-errormessages-more-readable">Print errormessages more readable</h2>



<p class="wp-block-paragraph">Do not fail the task itself, it is very usually unreadable because all information is printed on one line.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="657" height="124" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/09/image-10.png" alt="" class="wp-image-40296" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/09/image-10.png 657w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/09/image-10-300x57.png 300w" sizes="auto, (max-width: 657px) 100vw, 657px" /></figure>



<p class="wp-block-paragraph">Instead, use<code> ignore_errors: true </code>and <code>failed_when: false</code> in the task. Do the errorhandling in a separate task with a customized errormessage. To print the multiline list of stdout_lines, use <code>debug:</code> otherwise you can directy use <code>ansible.builtin.fail: </code>with a customized <code>message: </code></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
    - name: force sqlplus to throw error because of missing environment
      ansible.builtin.shell: |
        /u00/app/oracle/product/19.7.0/bin/sqlplus -L / as sysdba @myscript.sql 2&gt;&amp;1
      register: checks
      ignore_errors: true
      failed_when: false

    - name: Check for errors of task before
      debug: var=checks.stdout_lines
      failed_when: checks.rc != 0 or &#039;ORA-&#039; in checks.stdout
      when: checks.rc != 0 or &#039;ORA-&#039; in checks.stdout
</pre></div>


<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="658" height="181" src="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/09/image-11.png" alt="" class="wp-image-40298" srcset="https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/09/image-11.png 658w, https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2025/09/image-11-300x83.png 300w" sizes="auto, (max-width: 658px) 100vw, 658px" /></figure>



<h2 class="wp-block-heading" id="h-re-run-failed-hosts">Re-run failed hosts</h2>



<p class="wp-block-paragraph">As an example for this scenario: A customer of mine will do an offline backup of the development databases. And I have to run an Ansible playbook against all databases. If the playbook for this host is run at the backup time, it will fail because the database is down. But after some minutes the database will be restarted. </p>



<p class="wp-block-paragraph">What we can do now?</p>



<p class="wp-block-paragraph">Wait until the database is up again. That is possible, see the example of <code>ansible.builtin.wait_for</code> in my blog post <a href="https://www.dbi-services.com/blog/parallel-execution-of-ansible-roles/">Parallel execution of Ansible roles</a>. But for this scenario it is a waste of time. The database can be stopped (not for backup) and will not be restarted within the next few minutes.</p>



<p class="wp-block-paragraph">Try later after a while. My playbook for all hosts (parallel forks=5) takes about 1 hour. The idea now is to remember the host with the stopped database and to continue with the next host. After the play finished for all hosts, restart the play for the remembered hosts.</p>



<ul class="wp-block-list">
<li>The 1st play running against all database hosts:</li>



<li>gets the status of the databases on the host</li>



<li>assigns the database instances to a <code>is_running</code> and a <code>not_open</code> list</li>



<li>Include the role to run against the running databases</li>



<li>Dynamically add the host to the group <code>re_run_if_not_open</code> if there are <code>not_open</code> databases</li>
</ul>



<ul class="wp-block-list">
<li>The next play only runs for the <code>re_run_if_not_open</code> group</li>



<li>Include the role to run against the (hopefully now running) databases</li>



<li>If the database then is still down, we assume it is stopped permanently.</li>
</ul>



<p class="wp-block-paragraph"></p>
<p>L’article <a href="https://www.dbi-services.com/blog/errorhandling-in-ansible/">Errorhandling in Ansible</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/errorhandling-in-ansible/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Automatisation for Oracle ZDM installation and update</title>
		<link>https://www.dbi-services.com/blog/automatisation-for-oracle-zdm-installation-and-update/</link>
					<comments>https://www.dbi-services.com/blog/automatisation-for-oracle-zdm-installation-and-update/#respond</comments>
		
		<dc:creator><![CDATA[Marc Wagner]]></dc:creator>
		<pubDate>Thu, 31 Jul 2025 06:31:15 +0000</pubDate>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Installation]]></category>
		<category><![CDATA[patching]]></category>
		<category><![CDATA[zdm]]></category>
		<category><![CDATA[zero downtime migration]]></category>
		<guid isPermaLink="false">https://www.dbi-services.com/blog/?p=39773</guid>

					<description><![CDATA[<p>Let&#8217;s have a look how we can install and update Oracle Zero Downtime Migration tool, and see how we can automatise it with ansible&#8230; Check ZDM build Let&#8217;s first see how we can check ZDM version using zdm cli. [zdm@zdmhost ~]$ zdmcli -v RHP_PT.ZDM21_LINUX.X64_221207.30 [zdm@zdmhost ~]$ zdmcli -build version: 21.0.0.0.0 full version: 21.4.0.0.0 patch version: [&#8230;]</p>
<p>L’article <a href="https://www.dbi-services.com/blog/automatisation-for-oracle-zdm-installation-and-update/">Automatisation for Oracle ZDM installation and update</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Let&#8217;s have a look how we can install and update Oracle Zero Downtime Migration tool, and see how we can automatise it with ansible&#8230;</p>



<span id="more-39773"></span>



<h3>Check ZDM build</h3>



<p class="wp-block-paragraph">Let&#8217;s first see how we can check ZDM version using zdm cli.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: [1,4]">
[zdm@zdmhost ~]$ zdmcli -v
RHP_PT.ZDM21_LINUX.X64_221207.30

[zdm@zdmhost ~]$ zdmcli -build
version: 21.0.0.0.0
full version: 21.4.0.0.0
patch version: 21.4.5.0.0
label date: 221207.30
ZDM kit build date: Mar 21 2024 22:07:12 UTC
CPAT build version: 24.6.0
[exauser@sva-oelexa501 ~]$
</pre>
</br>



<p class="wp-block-paragraph">Version installed is 21.4, and we would see how to update it to last current version, which is 21.5.</p>



<h3>Manuel installation and update</h3>



<p class="wp-block-paragraph">Manuel installation and update is quite easy as it will be done through the <code>zdminstall.sh</code> script. It will be the option that will highlight if it is a first installation or an update. For a first installation, the option will be <code>setup</code> and for an update it will be <code>update</code>.</p>



<h3>Automatisation of the installation and update of ZDM</h3>



<p class="wp-block-paragraph">The playbook to automatise the installation and the update, in my case named <code>deploy_zdm.yml</code>, is composed of following tasks.</p>



<p class="wp-block-paragraph">We start by defining the playbook and the variable that will be used in the included tasks to install or update to zdm current last version, which is 21.5. The zip file to unarchive will be stored in the <code>../oracle_swfiles</code> directory.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: []">
---
# Playbook for deploying ZDM host
# Marc Wagner - dbi
# Date : 06.10.2023
# 11.06.2025 : stop service + new 21.5 version
- name: Deploy ZDM
  hosts: "zdmhost"
  vars:
    sfw_folder: "../oracle_swfiles"


    zdm_base: "/u01/app/oracle"
    zdm_install_dir: "zdm21.5"
    zdm_download_dir: "/u01/app/zdm_download_dir"
    zdm_archive: "{{ sfw_folder }}/V1045330-01.zip"

    # ZDM update is an in-place process
    zdm_home: "/u01/app/oracle/product/zdm"
  environment:
    HTTP_PROXY: ""
    HTTPS_PROXY: ""

  tasks:

</pre>
</br>



<p class="wp-block-paragraph">Then we will have all the tasks performing the installation.</p>



<p class="wp-block-paragraph">The first one will be used to define the variable for the option provided as extra argument of the ansible playbook. And we will assert that the variable is provided.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: []">
- name: Assert extra-var has been passed as argument to playbook
  ansible.builtin.assert:
    that:
      - deploy_option is defined
    quiet: false
    fail_msg: "Please provide --extra-var deploy_option="
    success_msg: "deploy_option={{ deploy_option }}"
</pre>
</br>



<p class="wp-block-paragraph">The next task will stop ZDM service and will only run if following file exists : <code>/u01/app/oracle/product/zdm/bin/zdmservice</code>.</p>



<p class="wp-block-paragraph">This check is done so the task will only run if ZDM tool is already installed.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: []">
- name: Stop ZDM service
  ansible.builtin.shell: |
    cmd: |
    {{ zdm_home }}/bin/zdmservice stop
  args:
    executable: "/bin/bash"
    removes: "/u01/app/oracle/product/zdm/bin/zdmservice"
</pre>
</br>



<p class="wp-block-paragraph">The next task will install some prerequisite if not already installed.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: []">
- name: Install ZDM software prerequisites
  become: true
  become_user: root
  ansible.builtin.dnf:
    name: "{{ item }}"
  loop:
    - perl
    - expect
    - libaio
    - glibc-devel
    - unzip
    - libnsl
    - ncurses-compat-libs
    - oraclelinux-developer-release-el8
</pre>
</br>



<p class="wp-block-paragraph">The next task will create all needed directories like zdm base, zdm home and the file used to store the installation archive file.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: []">
- name: Create directories for ZDM tool
  become: true
  become_user: root
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    owner: exauser
    group: exauser
    mode: '755'
  loop:
    - "{{ zdm_base }}"
    - "{{ zdm_home }}"
    - "{{ zdm_download_dir }}"
</pre>
</br>



<p class="wp-block-paragraph">The next task will unarchive the installation zip file.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: []">
- name: Unarchive ZDM
  ansible.builtin.unarchive:
    src: "{{ zdm_archive }}"
    dest: "{{ zdm_download_dir }}"
</pre>
</br>




<p class="wp-block-paragraph">And the next task will finally installed or update zdm tool according to the option given to the playbook.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: []">
- name: Install or update ZDM
  ansible.builtin.shell:
    cmd: |
      {{ zdm_download_dir }}/{{ zdm_install_dir }}/zdminstall.sh \
        {{ deploy_option }} oraclehome={{ zdm_home }} oraclebase={{ zdm_base }} \
        ziploc={{ zdm_download_dir }}/{{ zdm_install_dir }}/zdm_home.zip -zdm
  args:
    executable: "/bin/bash"
</pre>
</br>



<p class="wp-block-paragraph">And we can finally with the last steps start ZDM service.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: []">
- name: Start ZDM service
  ansible.builtin.shell: |
    cmd: |
    {{ zdm_home }}/bin/zdmservice start
  args:
    executable: "/bin/bash"
</pre>
</br>



<h3>Run the playbook</h3>



<p class="wp-block-paragraph">As prerequisite, let&#8217;s first check that the appropriate ZDM installation zip file is in the expected ansible folder.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: [1]">
[myuser@domain.com@admin-host zdm_ansible]$ ls -ltrh ./oracle_swfiles/
total 874M
-rw-r--r--. 1 myuser@domain.com myuser@domain.com 871M Jun 11 10:12 V1045330-01.zip
[myuser@domain.com@admin-host zdm_ansible]$
</pre>
</br>



<p class="wp-block-paragraph">We can check that the assert task to ensure we put the appropriate &#8211;extra-vars works.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: [1]">
[myuser@domain.com@admin-host zdm_ansible]$ ansible-playbook ./playbooks/deploy_zdm.yml

PLAY [Deploy ZDM] ***********************************************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************************************************************************************
[WARNING]: Platform linux on host zdmhost is using the discovered Python interpreter at /usr/bin/python3, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-
core/2.15/reference_appendices/interpreter_discovery.html for more information.
ok: [zdmhost]

TASK [Assert extra-var has been passed as argument to playbook] *************************************************************************************************************************************************************************************************************************
fatal: [zdmhost]: FAILED! =&gt; {"msg": "The task includes an option with an undefined variable. The error was: 'deploy_option' is undefined. 'deploy_option' is undefined\n\nThe error appears to be in '/home/nfs/domain.com/myuser/ExaCCGit/zdm_ansible/playbooks/deploy_zdm.yml': line 25, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n    - name: Assert extra-var has been passed as argument to playbook\n      ^ here\n"}

PLAY RECAP ******************************************************************************************************************************************************************************************************************************************************************************
zdmhost              : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

[myuser@domain.com@admin-host zdm_ansible]$
</pre>
</br>



<p class="wp-block-paragraph">Then we can run the playbook with the update option.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: [1]">
[myuser@domain.com@admin-host zdm_ansible]$ ansible-playbook ./playbooks/deploy_zdm.yml -e deploy_option="update"

PLAY [Deploy ZDM] ***********************************************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************************************************************************************
[WARNING]: Platform linux on host zdmhost is using the discovered Python interpreter at /usr/bin/python3, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-
core/2.15/reference_appendices/interpreter_discovery.html for more information.
ok: [zdmhost]

TASK [Assert extra-var has been passed as argument to playbook] *************************************************************************************************************************************************************************************************************************
ok: [zdmhost] =&gt; {
    "changed": false,
    "msg": "deploy_option=update"
}

TASK [Stop ZDM service] *****************************************************************************************************************************************************************************************************************************************************************
changed: [zdmhost]

TASK [Install ZDM software prerequisites] ***********************************************************************************************************************************************************************************************************************************************
ok: [zdmhost] =&gt; (item=perl)
ok: [zdmhost] =&gt; (item=expect)
ok: [zdmhost] =&gt; (item=libaio)
ok: [zdmhost] =&gt; (item=glibc-devel)
ok: [zdmhost] =&gt; (item=unzip)
ok: [zdmhost] =&gt; (item=libnsl)
ok: [zdmhost] =&gt; (item=ncurses-compat-libs)
ok: [zdmhost] =&gt; (item=oraclelinux-developer-release-el8)

TASK [Create directories for ZDM tool] **************************************************************************************************************************************************************************************************************************************************
ok: [zdmhost] =&gt; (item=/u01/app/oracle)
ok: [zdmhost] =&gt; (item=/u01/app/oracle/product/zdm)
ok: [zdmhost] =&gt; (item=/u01/app/zdm_download_dir)

TASK [Unarchive ZDM] ********************************************************************************************************************************************************************************************************************************************************************
ok: [zdmhost]

TASK [Install or update ZDM] ************************************************************************************************************************************************************************************************************************************************************
changed: [zdmhost]

TASK [Start ZDM service] ****************************************************************************************************************************************************************************************************************************************************************
changed: [zdmhost]

PLAY RECAP ******************************************************************************************************************************************************************************************************************************************************************************
zdmhost              : ok=8    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
</pre>
</br>



<h3>Check new ZDM version</h3>



<p class="wp-block-paragraph">And we can check that the new ZDM tool version is 21.5.</p>



<pre class="brush: sql; gutter: true; first-line: 1; highlight: [1,4]">
[zdm@zdmhost ~]$ zdmcli -v
RHP_PT.ZDM21_LINUX.X64_240219.12

[zdm@zdmhost ~]$ zdmcli -build
version: 21.0.0.0.0
full version: 21.5.0.0.0
patch version: N/A
label date: 240219.12
ZDM kit build date: Sep 10 2024 21:59:18 UTC
CPAT build version: 24.6.0
[zdm@zdmhost ~]$
</pre>
</br>



<h3>To wrap up&#8230;</h3>



<p class="wp-block-paragraph">Installing and updating ZDM cli is quite easy, and writing an ansible playbook will help automatising the installation and further update.</p>
<p>L’article <a href="https://www.dbi-services.com/blog/automatisation-for-oracle-zdm-installation-and-update/">Automatisation for Oracle ZDM installation and update</a> est apparu en premier sur <a href="https://www.dbi-services.com/blog">dbi Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dbi-services.com/blog/automatisation-for-oracle-zdm-installation-and-update/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 
Lazy Loading (feed)

Served from: www.dbi-services.com @ 2026-06-24 01:42:46 by W3 Total Cache
-->