<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[CTO and Sellout]]></title><description><![CDATA[A mixture of technical leadership articles and hands on fun with platform/cloud engineering topics]]></description><link>https://blog.ctoandsellout.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 20 May 2026 03:29:49 GMT</lastBuildDate><atom:link href="https://blog.ctoandsellout.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[AI thoughts - From Fear to Opportunity]]></title><description><![CDATA[As the world embraces artificial intelligence (AI), many people, especially those in the technology industry (including me 😨), are understandably concerned about its potential impact on jobs. The fear of AI replacing human workers has been a recurri...]]></description><link>https://blog.ctoandsellout.com/ai-thoughts-from-fear-to-opportunity</link><guid isPermaLink="true">https://blog.ctoandsellout.com/ai-thoughts-from-fear-to-opportunity</guid><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[AI]]></category><category><![CDATA[google cloud]]></category><dc:creator><![CDATA[James Heggs]]></dc:creator><pubDate>Tue, 05 Dec 2023 11:51:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1701777057740/2f461c85-27d0-4f06-bf79-937ea7514d77.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As the world embraces artificial intelligence (AI), many people, especially those in the technology industry (including me 😨), are understandably concerned about its potential impact on jobs. The fear of AI replacing human workers has been a recurring theme in science fiction and popular culture, and it's not surprising that some people feel anxious about the possibility of AI taking over our livelihoods.</p>
<p>We see tools like <a target="_blank" href="https://github.com/features/copilot">Co-pilot</a>, GitHub stating that they are <a target="_blank" href="https://github.blog/2023-11-08-universe-2023-copilot-transforms-github-into-the-ai-powered-developer-platform/">now an AI company</a> or the ever-talked-about soap opera that is ChatGPT and their ability to code so we wonder about where that leaves us.</p>
<p>As an engineer, I believe we will become inefficient if we don't leverage these tools. That isn't to say they should replace learning tools and languages, absolutely not! But we can use them to do some of the repetitive parts like code generation for human review.</p>
<p>Micro scale thoughts but what about looking wider and larger problem spaces...</p>
<p>It's important to remember that AI is not a monolithic entity. Rather, it's a collection of tools and technologies that can be used for a wide variety of purposes. While some AI applications may automate tasks that are currently performed by humans, others will create <strong>new opportunities that require new skills and expertise</strong>.</p>
<p>Google just released a new blog - "<a target="_blank" href="https://cloud.google.com/blog/topics/sustainability/cop28-google-cloud-partners-using-ai-for-sustainability">Google Cloud Partners Using AI for Sustainability</a>" which highlights two examples of how AI is being used to create new opportunities in the technology industry. Actually using technology for good!</p>
<p>ESG Book is using AI to help investors make informed decisions about sustainable investments, while Watershed is using AI to develop predictive models that can help businesses optimize their energy use.</p>
<p>These are just two examples of the many ways in which AI is being used to create new jobs in the technology industry. As AI continues to develop, we can expect to see even more new opportunities emerge.</p>
<p>Of course, the transition to an AI-powered workforce will not be without its challenges. Some jobs will undoubtedly be lost to automation, and workers will need to adapt to the changing landscape of the technology industry. Being truly honest, I hate this part - I hope we retain the human spirit though and those skills that just cannot be performed by automation - creativity, passion, art - all the things that make us human.</p>
<p>However, there is also reason to be optimistic about the future of tech jobs.</p>
<p>AI is not just a threat to jobs; it's also a powerful tool that can be used to create new opportunities. By embracing AI and developing the skills needed to work with it, tech workers can ensure that they are well-positioned for success in the years to come.</p>
<p>Here are some specific tips for tech workers who are concerned about the impact of AI on their jobs:</p>
<ul>
<li><p><strong>Develop strong technical skills.</strong> This includes programming, data analysis, and machine learning.</p>
</li>
<li><p><strong>Stay up-to-date on the latest AI trends.</strong> This will help you to identify new opportunities and adapt to the changing landscape of the industry.</p>
</li>
<li><p><strong>Be willing to learn new things.</strong> AI is constantly evolving, so you will need to be open to learning new skills and technologies.</p>
</li>
<li><p><strong>Focus on your creativity and problem-solving skills.</strong> These are skills that AI cannot easily replicate.</p>
</li>
</ul>
<p>By following these tips, tech workers can ensure that they are well-positioned for success in the AI-driven economy of the future.</p>
]]></content:encoded></item><item><title><![CDATA[Thoughts on Terraform licence]]></title><description><![CDATA[Terraform, a popular open-source infrastructure as code (IaC) tool, recently announced a change to its licensing model. Starting January 1, 2023, Terraform will be licensed under the HashiCorp Business Source License (HBSL). This change has been met ...]]></description><link>https://blog.ctoandsellout.com/thoughts-on-terraform-licence</link><guid isPermaLink="true">https://blog.ctoandsellout.com/thoughts-on-terraform-licence</guid><category><![CDATA[Terraform]]></category><category><![CDATA[License]]></category><dc:creator><![CDATA[James Heggs]]></dc:creator><pubDate>Thu, 02 Nov 2023 17:24:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698944055362/d75a152e-d073-4811-88ea-6772ce112e84.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Terraform, a popular open-source infrastructure as code (IaC) tool, recently announced a change to its licensing model. Starting January 1, 2023, Terraform will be licensed under the HashiCorp Business Source License (HBSL). This change has been met with mixed reactions from the community, with understandably some members expressing concerns.</p>
<p>In fact, it even triggered an open-source fork of Terraform called <a target="_blank" href="https://opentofu.org/">Open Tofu</a></p>
<h2 id="heading-why-the-open-source-community-is-upset"><strong>Why the Open Source Community is Upset</strong></h2>
<p>From what I can deduce, there are several reasons why some members of the Terraform community are upset about the change to HBSL.</p>
<ul>
<li><p><strong>HBSL restricts the use of Terraform in commercial products.</strong> While HBSL is a permissive license, it does require commercial users to agree to certain terms, such as providing support for Terraform and not using it to compete with HashiCorp's commercial offerings. This has led some to worry that the change will make it more difficult to use Terraform in commercial products and that it will stifle innovation.</p>
</li>
<li><p><strong>HashiCorp has not been transparent about the reasons for the change.</strong> There has been some speculation that HashiCorp is trying to lock in its customers and prevent them from using Terraform alternatives. However, HashiCorp has not publicly stated its reasons for the change.</p>
</li>
<li><p><strong>The change has been made without community input.</strong> The Terraform community has been largely excluded from the decision-making process surrounding the change to HBSL. This has led to some feeling that HashiCorp is not respecting the community's input and that the change is being made in a self-serving way.</p>
</li>
</ul>
<h2 id="heading-the-contrasting-perspective"><strong>The contrasting perspective</strong></h2>
<p>I wonder if the crux of things is because of the <strong>change</strong>. We're not super great with change especially when it's unexpected. I remember reading once that it isn't the act that hurts when trust is damaged but rather it is the surprise of the damage that hurts.</p>
<p>That being said, commercial hat on, I can understand a perspective of being slightly miffed that competing products (once you've decided that revenue is important) are using the ground you've laid to make their competitor.</p>
<p>There could however be potential benefits of the change.</p>
<p>On the one hand, the change to HBSL could make it more difficult for commercial users to use Terraform. This could lead to some users switching to alternative IaC tools. However, it is important to note that HBSL is still a permissive license and that it still allows for a wide range of use cases. Additionally, there are a number of other open-source IaC tools available that can be used in commercial products.</p>
<p>On the other hand, the change to HBSL could give HashiCorp more flexibility to develop and innovate Terraform. It could also make it easier for HashiCorp to attract commercial support for Terraform. This could ultimately benefit the Terraform community as a whole.</p>
<p>Overall, I believe that the change to HBSL is a mixed bag for the Terraform community. There are potential benefits and drawbacks, and it is important to weigh these carefully. I hope that HashiCorp will continue to engage with the community and address the concerns that have been raised.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>The change to HBSL is a significant change for the Terraform community. It is important for HashiCorp to continue to engage with the community and address the concerns that have been raised. I hope that the community will be able to work together to ensure that Terraform remains a thriving open-source project.</p>
]]></content:encoded></item><item><title><![CDATA[Terraform unit testing]]></title><description><![CDATA[Intro
As of Terraform v1.6 and later, there is now native support for writing tests. This guide shows how to start writing unit tests with Terraform.
You might already be familiar with aspects like mocking dependencies when doing unit testing within ...]]></description><link>https://blog.ctoandsellout.com/terraform-unit-testing</link><guid isPermaLink="true">https://blog.ctoandsellout.com/terraform-unit-testing</guid><category><![CDATA[Terraform]]></category><category><![CDATA[Testing]]></category><category><![CDATA[unit testing]]></category><category><![CDATA[Infrastructure as code]]></category><dc:creator><![CDATA[James Heggs]]></dc:creator><pubDate>Sun, 29 Oct 2023 16:46:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698527113012/aaa6f1cd-c277-4446-8584-0af150c2c106.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-intro">Intro</h3>
<p>As of <a target="_blank" href="https://developer.hashicorp.com/terraform/language/tests">Terraform v1.6</a> and later, there is now native support for writing tests. This guide shows how to start writing unit tests with Terraform.</p>
<p>You might already be familiar with aspects like mocking dependencies when doing unit testing within software development projects and how it differs from integration testing.</p>
<p>With infrastructure testing, the definition of a unit test is the ability to test logic within your code <strong>before</strong> it is applied. Specifically for Terraform, this means checking the <code>plan</code> that Terraform generates and NOT <code>apply</code>ing the infrastructure changes.</p>
<p>I'll do a future post on integration tests when the infrastructure has been applied.</p>
<h3 id="heading-tldr">TL;DR</h3>
<p>GitHub link to the code</p>
<p><a target="_blank" href="https://github.com/eggsy84/terraform_unit_testing_gcp">https://github.com/eggsy84/terraform_unit_testing_gcp</a></p>
<h3 id="heading-scenario">Scenario</h3>
<p>For this guide, rather than a simple main.tf that creates a storage bucket or something like that, let's assume that you have a Terraform project that makes use of local modules. One of those modules you've called <strong>networking</strong> and creates the VPC setup.</p>
<p>The root main.tf will make use of the <strong>networking</strong> module and for now, I'll just have the networking module create a VPC and a couple of subnets.</p>
<p>This is the directory structure</p>
<pre><code class="lang-bash">├── README.md
├── main.tf
├── modules
│   ├── networking
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── providers.tf
│   │   └── variables.tf
├── outputs.tf
├── providers.tf
└── variables.tf
</code></pre>
<h3 id="heading-the-module-and-usage">The module and usage</h3>
<p>The <a target="_blank" href="https://github.com/eggsy84/terraform_unit_testing_gcp/tree/main/modules/networking">networking module</a> has been created to create a VPC and two subnets within that VPC - one for a production network and one for the development network.</p>
<p>The module takes in <a target="_blank" href="https://github.com/eggsy84/terraform_unit_testing_gcp/blob/main/modules/networking/variables.tf">two variables</a> and using some string-based logic, <a target="_blank" href="https://github.com/eggsy84/terraform_unit_testing_gcp/blob/main/modules/networking/main.tf">names the subnets</a> as per <a target="_blank" href="https://cloud.google.com/architecture/best-practices-vpc-design#naming">Google naming recommendations</a>.</p>
<p>To test this module you can expect that one of the "units" you might wish to test is that the subnets abide by the naming conventions.</p>
<p>Here's the code of the module</p>
<pre><code class="lang-apache"><span class="hljs-comment"># Example networking module creates a dev and production subnet</span>
<span class="hljs-comment"># with a specified region. </span>
<span class="hljs-comment"># Naming style for networks loosely based on Google Best Practices</span>
<span class="hljs-comment"># https://cloud.google.com/architecture/best-practices-vpc-design#naming</span>

<span class="hljs-attribute">resource</span> <span class="hljs-string">"google_compute_network"</span> <span class="hljs-string">"vpc_network"</span> {
  <span class="hljs-attribute">name</span>                      = <span class="hljs-string">"${var.company_name}-app"</span>
  <span class="hljs-attribute">description</span>               = <span class="hljs-string">"VPC network for the ${var.company_name} app"</span>
  <span class="hljs-attribute">auto_create_subnetworks</span>   = false
}

<span class="hljs-comment"># Example name for europe-west2 and company name Acme company app</span>
<span class="hljs-comment"># acme-app-eu-we2-prod-subnet</span>
<span class="hljs-comment"># acme-app-eu-we2-dev-subnet</span>
<span class="hljs-attribute">resource</span> <span class="hljs-string">"google_compute_subnetwork"</span> <span class="hljs-string">"dev"</span> {
  <span class="hljs-attribute">name</span>          = <span class="hljs-string">"${var.company_name}-app-${substr(var.region, 0, 2)}-${substr(regex("</span>-[a-z]+<span class="hljs-string">", var.region), 1, 2)}${substr(var.region, length(var.region) -1, 1)}-dev-subnet"</span>
  <span class="hljs-attribute">ip_cidr_range</span> = <span class="hljs-string">"10.128.0.0/20"</span>
  <span class="hljs-attribute">region</span>        = var.region
  <span class="hljs-attribute">network</span>       = google_compute_network.vpc_network.id
}

<span class="hljs-attribute">resource</span> <span class="hljs-string">"google_compute_subnetwork"</span> <span class="hljs-string">"prod"</span> {
  <span class="hljs-attribute">name</span>          = <span class="hljs-string">"${var.company_name}-app-${substr(var.region, 0, 2)}-${substr(regex("</span>-[a-z]+<span class="hljs-string">", var.region), 1, 2)}${substr(var.region, length(var.region) -1, 1)}-prod-subnet"</span>
  <span class="hljs-attribute">ip_cidr_range</span> = <span class="hljs-string">"10.154.0.0/20"</span>
  <span class="hljs-attribute">region</span>        = var.region
  <span class="hljs-attribute">network</span>       = google_compute_network.vpc_network.id
}
</code></pre>
<h3 id="heading-the-unit-test">The unit test</h3>
<p>Looking at how the subnet names are defined, it feels like some business logic that should be tested and a good case for a unit case. We might want to test out some of that crazy string logic around different regions and company names.</p>
<p>In this guide, I'll take the approach that tests of the networking module are considered unit tests and shall be located within the module directory. In a later post, we'll create integration tests that sit within the root directory.</p>
<p>With that in mind, create a new directory within the networking module called <strong>tests</strong> and create a new file within that directory, let's call it <strong>naming_convention.tftest.hcl</strong></p>
<p>The directory structure now looks similar to this:</p>
<pre><code class="lang-bash">.
├── README.md
├── main.tf
├── modules
│   └── networking
│       ├── main.tf
│       ├── outputs.tf
│       ├── provider.tf
│       ├── tests
│       │   └── naming_convention.tftest.hcl
│       └── variables.tf
├── outputs.tf
├── providers.tf
└── variables.tf
</code></pre>
<p>Let's create the first test, within the <strong>naming_convention.tftest.hcl</strong> file</p>
<pre><code class="lang-apache"><span class="hljs-attribute">variables</span> {
  <span class="hljs-attribute">company_name</span>  = <span class="hljs-string">"acme"</span>
  <span class="hljs-attribute">region</span>        = <span class="hljs-string">"europe-west2"</span>
  <span class="hljs-attribute">project_id</span>    = <span class="hljs-string">"example"</span>
}

<span class="hljs-attribute">run</span> <span class="hljs-string">"valid_naming_convention"</span> {

  <span class="hljs-attribute">command</span> = plan

  <span class="hljs-attribute">assert</span> {
    <span class="hljs-attribute">condition</span>     = google_compute_subnetwork.dev.name == <span class="hljs-string">"acme-app-eu-we2-dev-subnet"</span>
    <span class="hljs-attribute">error_message</span> = <span class="hljs-string">"Dev subnet name did not match expected naming convention"</span>
  }

  <span class="hljs-attribute">assert</span> {
    <span class="hljs-attribute">condition</span>     = google_compute_subnetwork.prod.name == <span class="hljs-string">"acme-app-eu-we2-prod-subnet"</span>
    <span class="hljs-attribute">error_message</span> = <span class="hljs-string">"Prod subnet name did not match expected naming convention"</span>
  }
}
</code></pre>
<p><strong>📝 NOTE:</strong> At the time of writing (2023-10), the Terraform VS Code plugin doesn't observe or support the test code syntax so don't worry if you have lots of red squiggles or a lack of syntax highlighting.</p>
<p>The above code initiates the required variables for the module and then runs a test to assert that the correct name is applied to the subnet.</p>
<p>The global variables can also be overridden by local test variables. For example, we might wish to test an alternative region:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">run</span> <span class="hljs-string">"valid_dev_naming_convention_alternative_region"</span> {

  <span class="hljs-attribute">command</span> = plan

  <span class="hljs-attribute">variables</span> {
    <span class="hljs-attribute">region</span>        = <span class="hljs-string">"asia-east1"</span>
  }

  <span class="hljs-attribute">assert</span> {
    <span class="hljs-attribute">condition</span>     = google_compute_subnetwork.dev.name == <span class="hljs-string">"acme-app-as-ea1-dev-subnet"</span>
    <span class="hljs-attribute">error_message</span> = <span class="hljs-string">"Dev subnet name did not match expected naming convention"</span>
  }
}
</code></pre>
<p>The full test file <a target="_blank" href="https://github.com/eggsy84/terraform_unit_testing_gcp/blob/main/modules/networking/tests/naming_convention.tftest.hcl">can be viewed on GitHub</a></p>
<h3 id="heading-running-the-test">Running the test</h3>
<p>The command you'll be using for executing the tests is <code>terraform test</code>. The command has various options which you can <a target="_blank" href="https://developer.hashicorp.com/terraform/cli/commands/test">find on the documentation</a>. At the time of writing it will, by default, look for a tests directory within the current working directory and execute tests from there. You can specify the <code>-test-directory</code> but it seems to read the terraform config relatively.</p>
<p>With this in mind, to run tests you've created within the networking module we'll navigate to it first, <code>init</code> the module (to ensure the GCP provider can be read) and then run <code>test</code></p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> modules/networking 

terraform init

terraform <span class="hljs-built_in">test</span>
</code></pre>
<p>You should then see Terraform read the tests and execute them</p>
<pre><code class="lang-bash">tests/naming_convention.tftest.hcl... <span class="hljs-keyword">in</span> progress
  run <span class="hljs-string">"valid_dev_naming_convention"</span>... pass
  run <span class="hljs-string">"valid_dev_naming_convention_alternative_region"</span>... pass
tests/naming_convention.tftest.hcl... tearing down
tests/naming_convention.tftest.hcl... pass

Success! 2 passed, 0 failed.
</code></pre>
<p>Hopefully, all is well, your tests ran and you can see some output.</p>
<p>In a future post, we'll add integration tests that bring together multiple modules and perform an integration test of things.</p>
]]></content:encoded></item></channel></rss>