<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ben Coleman</title>
    <description>The latest articles on DEV Community by Ben Coleman (@bencodegeek).</description>
    <link>https://dev.to/bencodegeek</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F264118%2F3eecd3aa-0e3d-4b2f-bbe4-f014eb764b5a.jpg</url>
      <title>DEV Community: Ben Coleman</title>
      <link>https://dev.to/bencodegeek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bencodegeek"/>
    <language>en</language>
    <item>
      <title>Contributing to the Azure Terraform Provider</title>
      <dc:creator>Ben Coleman</dc:creator>
      <pubDate>Wed, 02 Dec 2020 17:21:11 +0000</pubDate>
      <link>https://dev.to/cse/contributing-to-the-azure-terraform-provider-bm6</link>
      <guid>https://dev.to/cse/contributing-to-the-azure-terraform-provider-bm6</guid>
      <description>&lt;p&gt;Ok so you're using Terraform to deploy and manage your Azure resources? It's pretty neat, but at some point it's likely you will stumble over an Azure resource or configuration that's not available in Terraform. The &lt;a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs" rel="noopener noreferrer"&gt;Terraform Provider for Azure&lt;/a&gt; covers a huge number of resources in Azure, but there's always going to be gaps, given how quickly Azure evolves.&lt;/p&gt;

&lt;p&gt;So what can you do? Well, you can find a workaround (like using Azure CLI or even ARM Templates), or raise an issue on the &lt;a href="https://github.com/terraform-providers/terraform-provider-azurerm" rel="noopener noreferrer"&gt;Azure Provider GitHub project&lt;/a&gt; and hope some kind soul picks it up, or &amp;lt;deep intake of breath&amp;gt; roll up your sleeves, open your IDE of choice (VS Code of course!) and start work on adding yourself.&lt;/p&gt;

&lt;p&gt;In this post I'll talk through some of the planning, pre-work and other technical investigation you're going to need to do, before you go diving headfirst into the code base. This is a replay of my own journey of adding to the provider, and trust me this isn't something you want to start doing without more than a little planning.&lt;/p&gt;

&lt;h1&gt;
  
  
  Basics &amp;amp; Pre-reqs
&lt;/h1&gt;

&lt;p&gt;In Dante's Inferno, he describes hell having nine different layers or circles. Thankfully we have just five to worry about, however the amount of suffering involved might be the same as a trip through Dante's vision of unending torment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fef6vminzj5epal3baany.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fef6vminzj5epal3baany.jpg" alt="The Nine Circles of Hell"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our layers are a little different, but no less infernal 😉&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Azure REST API Spec&lt;/strong&gt; - &lt;a href="https://github.com/Azure/azure-rest-api-specs" rel="noopener noreferrer"&gt;This repo contains OpenAPI specifications for all the Azure APIs&lt;/a&gt;. These specs are OpenAPI/Swagger definitions which describe shape of every API in Azure. Despite being at the top of this stack, most of the time you can pretty much ignore this, unless you think you've hit a bug with the way the API is behaving.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Azure REST API&lt;/strong&gt; - This is the main management interface to Azure and implements the above API spec. This is going to dictate &amp;amp; shape everything else we touch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure SDK for Go&lt;/strong&gt; - This wraps the above Azure API with a set of packages &amp;amp; client code making it "easier" than calling the API directly. Easier is matter of some debate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform Provider for Azure&lt;/strong&gt; - Also called 'azurerm' (which is the provider name), this in turn wraps the Go SDK, with a set of CRUD operations that Terraform understands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform&lt;/strong&gt; - The Azure provider is a plugin and extension to the core Terraform system&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Needless you say you're going to need some Terraform experience, at least with the basics. It's also worth reading the &lt;a href="https://www.terraform.io/docs/plugins/provider.html" rel="noopener noreferrer"&gt;docs on provider plugins&lt;/a&gt; to get familiar with the concepts and main interfaces around providers.&lt;/p&gt;

&lt;p&gt;You're also going to need to be able to program in Go. You won't need to be a Go uber-coder, but if you've never touched it, you're going to have a very rough time, this is not the sort project in which I would advise you start learning Go with.&lt;/p&gt;

&lt;p&gt;It also helps if you've some prior experience with the Azure REST APIs (also called the ARM APIs), such as how they are versioned, the sorts of operations you can perform and concepts such as authentication, resource providers, scopes etc.&lt;/p&gt;

&lt;p&gt;So brave traveller, are you ready to descend?&lt;/p&gt;

&lt;h1&gt;
  
  
  The Azure API
&lt;/h1&gt;

&lt;p&gt;First you need to identify the API or APIs in Azure that are going plug the gap you need. This might be something you can deploy or configure from the Azure portal, the CLI but not through Terraform. You're going to spend a &lt;em&gt;lot&lt;/em&gt; of time in this section of the Azure docs &lt;a href="https://docs.microsoft.com/en-us/rest/api/azure/" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/rest/api/azure/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's assume you find what you need (if you didn't your journey has been a short one!)&lt;/p&gt;

&lt;p&gt;Take &lt;strong&gt;plenty&lt;/strong&gt; of time to research the API, try it out &amp;amp; experiment with it. My suggestion is to use the fantastic &lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" rel="noopener noreferrer"&gt;REST Client for VS Code&lt;/a&gt;. Build up a set of calls in a &lt;code&gt;.http&lt;/code&gt; or &lt;code&gt;.rest&lt;/code&gt; file which you can refer back to&lt;/p&gt;

&lt;p&gt;I wrote a short post on using this extension to authenticate and call Azure APIs, and how easy it makes it - so it's worth referring to that&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/cse" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3328%2F154c1f2d-df08-409b-b8e0-7d1dfd4762d4.png" alt="CSE Dev Crews"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F264118%2F3eecd3aa-0e3d-4b2f-bbe4-f014eb764b5a.jpg" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/cse/calling-azure-apis-with-rest-extension-for-vs-code-bhn" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Calling Azure APIs with the REST Extension for VS Code &lt;/h2&gt;
      &lt;h3&gt;Ben Coleman for CSE Dev Crews ・ Nov 18 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#azure&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rest&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#vscode&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Test the API thoroughly, time spent here will time well spent later. Poke at all the edge cases, "what if that array is empty?", "what if I put an invalid string here?", "if I remove that value, what is the default?". The docs will be some help, but generally are pretty bare bones.&lt;/p&gt;

&lt;p&gt;Once you're happy that you've got good a handle on calling the API directly, it's time to move on to the next layer...&lt;/p&gt;

&lt;p&gt;So traveller, I see you are prepared to descend deeper, let us journey on?&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkyc785geazeqg1m2y2dd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkyc785geazeqg1m2y2dd.jpg" alt="Gustave Dore illustration from the Divine Comedy"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Build Go Prototype / Code Spike
&lt;/h1&gt;

&lt;p&gt;The temptation might be to now jump into the Terraform provider code, but I'd hold off. Next it's worth spending some time working with the Azure SDK for Go to call the API in question&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Azure" rel="noopener noreferrer"&gt;
        Azure
      &lt;/a&gt; / &lt;a href="https://github.com/Azure/azure-sdk-for-go" rel="noopener noreferrer"&gt;
        azure-sdk-for-go
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This repository is for active development of the Azure SDK for Go. For consumers of the SDK we recommend visiting our public developer docs at:
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The Go SDK is auto-generated from the aforementioned Azure REST API Spec, this means it's not exactly the most friendly SDK to work with. And with extremely rigid adherence to having everything well typed, means it can be laborious work to even see what the API is returning.&lt;/p&gt;

&lt;p&gt;I would suggest using a &lt;a href="https://en.wikipedia.org/wiki/Spike_(software_development)" rel="noopener noreferrer"&gt;code spike approach&lt;/a&gt; and build a simple console Go app, and in doing so take a look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which package in the SDK you need, as they are versioned to match the Azure API versions, but it can be a challenge to even find the right package in the complex tree within the SDK.&lt;/li&gt;
&lt;li&gt;How the API client in that package is instantiated, normally with a subscription ID and possibly location, but each client is different.&lt;/li&gt;
&lt;li&gt;Make calls to the create, update and get operations. It's important you know how to build the input struct for a create operation, which might not be as trivial as it sounds. Also how to extract data from the response, which can often involve some "walking" down through all the properties and casting/asserting as you go&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This might seem like busy work and a waste of time, but you'll learn a lot in doing this, and it's much easier to test at this point before needing to go through an entire Terraform plan &amp;amp; apply loop. In addition a lot of this code you'll be able to copy and paste into the provider code.&lt;/p&gt;

&lt;p&gt;Are you confident to push on, to our final infernal layer?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbnb5y8mq0pwyhhn9bnef.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbnb5y8mq0pwyhhn9bnef.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Azure Terraform Provider
&lt;/h1&gt;

&lt;p&gt;The final part of the "journey", but there's still a long way to go - as this part will by far take the longest. I'm not going to go super deep into the low level code &amp;amp; implementation specifics in this section, that could fill another post (or in fact several!), instead I want to focus on the design, approach &amp;amp; thinking you'll need to do.&lt;/p&gt;

&lt;p&gt;Start with designing the shape of your resource, sketch out some pseudo code HCL. By now you've probably got a good idea what this will look like based on the body of your API requests, but think about if you can make it a little more user friendly. For example where it comes to field names, think what does the end user likely know this field/feature by? There can often be a disconnect between the "internal" names used in the API and the "external" names used in the Portal &amp;amp; CLI&lt;/p&gt;

&lt;p&gt;One area to consider is where the API accepts an array of objects, this can be simplified in the HCL as a repeated block with the same name, this will automatically become an array. Therefor you will need to switch from a pluralized name to a singular. For example&lt;/p&gt;

&lt;p&gt;Example API JSON payload&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rule 1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rule 2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Example equivalent Terraform HCL&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="nx"&gt;azurerm_amazing_new_thing&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rule 1"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rule 2"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Moving onward finally to the provider code itself which is hosted here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/hashicorp" rel="noopener noreferrer"&gt;
        hashicorp
      &lt;/a&gt; / &lt;a href="https://github.com/hashicorp/terraform-provider-azurerm" rel="noopener noreferrer"&gt;
        terraform-provider-azurerm
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Terraform provider for Azure Resource Manager
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You're contributing to a public open source project on GitHub, ultimately ending with a pull request which (hopefully!) will be merged into in main codebase and released. There's a certain way of working when contributing to OSS projects, there's plenty of guides online to help with this, e.g. &lt;a href="https://github.com/firstcontributions/first-contributions" rel="noopener noreferrer"&gt;first-contributions&lt;/a&gt; and &lt;a href="https://github.com/MarcDiethelm/contributing" rel="noopener noreferrer"&gt;MarcDiethelm/contributing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take plenty of time to explore the codebase, but thankfully you don't need to understand it all, focus on digging into the &lt;a href="https://github.com/terraform-providers/terraform-provider-azurerm/tree/master/azurerm/internal/services" rel="noopener noreferrer"&gt;azurerm/internal/services&lt;/a&gt; tree. Take some time to look at some Azure resources you are familiar with, try to find something not too complex (e.g. App Service) but not so simple it's trivial.&lt;/p&gt;

&lt;p&gt;The resources are grouped by their Azure Provider API, and under each group there will be some shared code common to all resources in that package. The key ones being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;registration.go&lt;/code&gt; - This should be a short file containing a &lt;code&gt;SupportedResources()&lt;/code&gt; function which maps the Terraform resource names e.g. &lt;code&gt;azurerm_new_thing&lt;/code&gt; to the Go function that provides that resource, e.g &lt;code&gt;resourceArmNewThing()&lt;/code&gt;. You should be able to copy and paste an existing line in here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client/client.go&lt;/code&gt; - This is where all the API clients from the SDK are created for the given API package, really it's another case of copy and pasting an existing one as there's a clear pattern to things.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementing your resource will be a matter of copying an existing one and making a LOT of changes. There will be a set of callback functions for the CRUD operations &lt;code&gt;Create&lt;/code&gt;, &lt;code&gt;Read&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt; and &lt;code&gt;Delete&lt;/code&gt;, implementing those functions is the heart of the task at hand, and &lt;a href="https://www.terraform.io/docs/plugins/provider.html" rel="noopener noreferrer"&gt;detailed here&lt;/a&gt;. Also the Schema is defined in here, this is the implementation of the HCL design we discussed a moment ago. You can &lt;a href="https://www.terraform.io/docs/extend/schemas/index.html" rel="noopener noreferrer"&gt;read the docs&lt;/a&gt; also take a good look at how other resources define their schemas, and learn by example&lt;/p&gt;

&lt;p&gt;Testing your code will take two shapes, informal testing locally with some Terraform HCL is the first place to start. In order to load your locally built version of the provider there's some hoops to jump though, which have been made a lot more difficult since Terraform 0.13.&lt;/p&gt;

&lt;p&gt;The script below I created helps with this, it builds the azurerm code, and then copies the resulting provider binary to where the Terraform CLI can find it. Runs &lt;code&gt;terraform init&lt;/code&gt; with &lt;code&gt;-plugin-dir&lt;/code&gt; set and then does a standard Terraform plan &amp;amp; apply&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build provider &amp;amp; load plugin test harness script:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/benc-uk/terraform-sandbox/blob/master/provider-test-harness/run.sh" rel="noopener noreferrer"&gt;https://github.com/benc-uk/terraform-sandbox/blob/master/provider-test-harness/run.sh&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note. In the script I pick a deliberately out of range version for the plugin as a belt and braces to make sure my copy is really being picked up, so the version of azurerm in your test Terraform would need to be &lt;code&gt;version = "&amp;gt;=99.0.0"&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You'll run this inner loop test many, MANY times until you get things working. The next set of tests are more formal acceptance tests. These live in the tests folder of the tree you are working in. All acceptance tests start with &lt;code&gt;TestAcc&lt;/code&gt; this means they won't run in the standard unit test cycle, they all contain embedded inline HCL which defines the test resources to create &amp;amp; destroy.&lt;/p&gt;

&lt;p&gt;These tests are only run when certain flags are specified, namely calling &lt;code&gt;make acctest&lt;/code&gt;. Again I suggest learning by example, copy some existing tests and build on what you find. Note these tests will deploy real resources in Azure which means they can be very slow to run and incur costs!&lt;/p&gt;

&lt;p&gt;The final stage before submitting your PR is to run though the test/check suite locally. This is done automatically in the &lt;a href="https://github.com/terraform-providers/terraform-provider-azurerm/actions" rel="noopener noreferrer"&gt;CI pipeline of the project in GitHub Actions&lt;/a&gt; however there's no point submitting your PR if the CI validation is going to fail, so get it working locally first, the main checks to run locally are:&lt;br&gt;&lt;br&gt;
&lt;code&gt;make tools&lt;/code&gt;, &lt;code&gt;make test&lt;/code&gt;, &lt;code&gt;make lint&lt;/code&gt;, &lt;code&gt;make tflint&lt;/code&gt;, &lt;code&gt;make depscheck&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These scripts can take a little while to run and tend hit your machine quite hard, but once they are passing, you can finally submit your PR! Sit back and wait for the team to check it over, and get back to your with feedback. Be patient they are a very busy team!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;PHEW! What a journey, but hopefully like Dante's Virgil you made it through unscathed! Undoubtedly you learned a lot in the process. Contributing to the Azure Terraform Provider isn't something you do lightly, but can be very rewarding.&lt;/p&gt;

&lt;p&gt;Your addition can make Terraform just a little bit better for everyone using Terraform with Azure, and for that reason alone it's sometimes worth going on a bit of an adventure&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>azurerm</category>
      <category>restapi</category>
    </item>
    <item>
      <title>Terraform Bootstrap &amp; Backend State in Azure</title>
      <dc:creator>Ben Coleman</dc:creator>
      <pubDate>Tue, 01 Dec 2020 16:54:32 +0000</pubDate>
      <link>https://dev.to/cse/terraform-bootstrap-backend-state-in-azure-5b73</link>
      <guid>https://dev.to/cse/terraform-bootstrap-backend-state-in-azure-5b73</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;When starting a new project utilising Terraform to manage resources in Azure, there's usually a hurdle to overcome, where you need to bootstrap your environment with certain pre-reqs. The main one of those being a way hold shared state (what Terraform calls a backend)&lt;/p&gt;

&lt;p&gt;To this end I'd like to share a set of scripts &amp;amp; Terraform to help you though this initial bootstrap &amp;amp; setup process&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/benc-uk"&gt;
        benc-uk
      &lt;/a&gt; / &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap"&gt;
        terraform-mgmt-bootstrap
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Bootstrap core Azure state &amp;amp; resources using Terraform for use with Azure DevOps
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The repo holds some reusable scripts and Terraform configuration to "bootstrap" a project in order to be able to start using Terraform with Azure. This paves the way for the set up of Azure DevOps Pipelines to deploy further resources. This aligns with the common "hub &amp;amp; spoke" style of Azure architecture. where one shared set of management resources are used to support the deployment and management of one or more spokes through automated CI/CD pipelines. &lt;/p&gt;

&lt;p&gt;In this case Azure DevOps is the CI/CD system we will be using &amp;amp; configuring&lt;/p&gt;

&lt;p&gt;These "spokes" could be separate subscriptions or simply multiple environments in different resource groups for hosting simultaneous instances of an app.&lt;/p&gt;

&lt;p&gt;Note. There is no dependency or relation to the &lt;a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/hub-spoke-network-topology"&gt;hub &amp;amp; spoke network topology&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's four main parts setup up by this process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bootstrap of backend state in Azure Storage for all Terraform to use.&lt;/li&gt;
&lt;li&gt;Deployment (and redeployment) set of shared, management resources.&lt;/li&gt;
&lt;li&gt;Creation of service principals with role assignments in Azure AD.&lt;/li&gt;
&lt;li&gt;Initial configuration of Azure DevOps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the scripts in the repo are intended to be run manually and infrequently, and called from an administrators local machine or Azure Cloud Shell. &lt;em&gt;There is no automation or CI/CD, this is by design&lt;/em&gt; - the purpose of this is to provide the bedrock to allow further CI/CD to happen.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note. This article is not intended as an intro to using Azure and Terraform, so it assumes a fair degree of knowledge in this area.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Pre-reqs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Bash&lt;/li&gt;
&lt;li&gt;Terraform 0.13+&lt;/li&gt;
&lt;li&gt;Azure CLI&lt;/li&gt;
&lt;li&gt;Authenticated connection to Azure, using Azure CLI, logged into the subscription you wish to configure&lt;/li&gt;
&lt;li&gt;Azure DevOps organization and project&lt;/li&gt;
&lt;li&gt;An Azure DevOps PAT token (full scope) for the relevant Azure DevOps organization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;Before running any of the scripts, the configuration and input variables need to be set. This is done in an &lt;code&gt;.env&lt;/code&gt; file, and this file is read and parsed by scripts&lt;/p&gt;

&lt;p&gt;Note. &lt;code&gt;.tfvars&lt;/code&gt; file is not used, this is intentional. The dotenv format is easier to parse, meaning we can use the values in bash scripts and for other purposes&lt;/p&gt;

&lt;p&gt;Copy the &lt;code&gt;.env.sample&lt;/code&gt; file to &lt;code&gt;.env&lt;/code&gt; and set values for all variables as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_state_storage&lt;/code&gt; - The name of the storage account to hold Terraform state.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_mgmt_res_group&lt;/code&gt; - The shared resource group for all hub resources, including the storage account.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_state_container&lt;/code&gt; - Name of the blob container to hold Terraform state (default: &lt;code&gt;tfstate&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_prefix&lt;/code&gt; - A prefix added to all resources, pick your project name or other prefix to give the resources unique names.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_region&lt;/code&gt; - Azure region to deploy all resources into.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_azdo_org_url&lt;/code&gt; - URL of Azure DevOps org to use, e.g. https&lt;span&gt;://dev.azure.com/foobar&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_azdo_project_name&lt;/code&gt; - Name of the Azure DevOps project in the above org.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_azdo_pat&lt;/code&gt; - &lt;a href="https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&amp;amp;tabs=preview-page"&gt;Azure DevOps access token&lt;/a&gt; with rights to create variable groups and service connections.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Bootstrap of Backend State
&lt;/h1&gt;

&lt;p&gt;As a principal we want all our resources defined in Terraform, including the storage account using by Terraform to hold backend state. This results in a chicken and egg problem.&lt;/p&gt;

&lt;p&gt;To solve this a bootstrap script is used which creates the initial storage account and resource group using the Azure CLI. Then Terraform is initialized pointing at this storage account as a backend, and the storage account imported into state&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap/blob/main/bootstrap.sh"&gt;bootstrap.sh&lt;/a&gt; in the GitHub repo for details&lt;/p&gt;

&lt;p&gt;This script should never need running a second time even if the other management resources are modified&lt;/p&gt;

&lt;h1&gt;
  
  
  Management Resource Deployment
&lt;/h1&gt;

&lt;p&gt;The deployment of the rest of the shared management resources is done via Terraform, and the various .tf files in the root of the repo.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap/blob/main/deploy.sh"&gt;deploy.sh&lt;/a&gt; in the GitHub repo for details&lt;/p&gt;

&lt;p&gt;This Terraform creates &amp;amp; configures the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource Group (also in bootstrap).&lt;/li&gt;
&lt;li&gt;Storage Account for holding Terraform state (also in bootstrap).&lt;/li&gt;
&lt;li&gt;Azure Container Registry. Not used but intended for providing centralized access to containers.&lt;/li&gt;
&lt;li&gt;Azure Log Analytics. Not used but intended for log aggregation &lt;/li&gt;
&lt;li&gt;Key Vault* for holding credentials and secrets used by Azure DevOps Pipelines.&lt;/li&gt;
&lt;li&gt;Service Principal, with RBAC role assignment to access the KeyVault "Key Vault Reader (preview)".&lt;/li&gt;
&lt;li&gt;A second Service Principal (to be used for pipelines), with IAM role "Contributor" at the subscription level.&lt;/li&gt;
&lt;li&gt;KeyVault access policy for above Service Principal to allow it to get &amp;amp; list secrets.&lt;/li&gt;
&lt;li&gt;KeyVault access policy for the current user to be able to manage secrets.&lt;/li&gt;
&lt;li&gt;Populates KeyVault with secrets, holding the credential details for the pipeline service principal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may wish to modify the role assigned to the pipeline service principal &lt;/p&gt;

&lt;h1&gt;
  
  
  Azure DevOps
&lt;/h1&gt;

&lt;p&gt;The deployment Terraform also sets up some initial configuration in Azure DevOps namely service connection called &lt;code&gt;keyvault-access&lt;/code&gt; which will allow variable groups to be linked to the KeyVault.&lt;/p&gt;

&lt;p&gt;The creation of a Azure DevOps variable group linked to KeyVault can not be done via Terraform or the Azure CLI. A work-around using cURL and REST API has been used. This is some what brittle but it serves the purpose well enough.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap/blob/main/azdo-var-group.sh"&gt;azdo-var-group.sh&lt;/a&gt; in the GitHub repo for details&lt;/p&gt;

&lt;p&gt;Running this script will create a variable group called &lt;code&gt;shared-secrets&lt;/code&gt; in the Azure DevOps project and populate it with four variables&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pipeline-sp-clientid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pipeline-sp-secret&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azure-tenant-id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azure-sub-id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These variables can be used in subsequent Azure DevOps pipelines.&lt;/p&gt;

&lt;h1&gt;
  
  
  Next Steps &amp;amp; Example Environment
&lt;/h1&gt;

&lt;p&gt;This repo is intended to lay the ground work for Azure DevOps pipelines to be set up to deploy further resources. The shared variable group is a key part of enabling this, but the configuration of those pipelines is something clearly project &amp;amp; environment specific, so is not covered further here.&lt;/p&gt;

&lt;p&gt;A working CD pipeline with demo Terraform is given in the &lt;code&gt;example/&lt;/code&gt; directory. This environment is nothing more than a resource group &amp;amp; a storage account for illustrative purposes. The focus is the pipeline file - &lt;code&gt;example/deploy.yaml&lt;/code&gt; this carries out the deployment as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses the above &lt;code&gt;shared-secrets&lt;/code&gt; variable group&lt;/li&gt;
&lt;li&gt;Runs using the service principal details held in Key Vault&lt;/li&gt;
&lt;li&gt;Keeps state in the management backend state storage account&lt;/li&gt;
&lt;li&gt;Carries out standard Terraform init / plan / apply&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refer to the &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap/blob/main/example/deploy.yaml"&gt;example/deploy.yaml&lt;/a&gt; file for further details&lt;/p&gt;

&lt;p&gt;If you are using a mono-repo, the whole of this repo can be dropped in as a sub-folder, in order to keep the Terraform separate from any Terraform you wish to use in your other pipelines.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>terraform</category>
      <category>devops</category>
    </item>
    <item>
      <title>Calling Azure APIs with the REST Extension for VS Code </title>
      <dc:creator>Ben Coleman</dc:creator>
      <pubDate>Wed, 18 Nov 2020 23:43:49 +0000</pubDate>
      <link>https://dev.to/cse/calling-azure-apis-with-rest-extension-for-vs-code-bhn</link>
      <guid>https://dev.to/cse/calling-azure-apis-with-rest-extension-for-vs-code-bhn</guid>
      <description>&lt;p&gt;The fantastic REST Client for VS Code is a popular and valuable tool when doing any work with a REST API, be it your own or a 3rd party. Using this extension you can define a set of HTTP calls in a &lt;code&gt;.http&lt;/code&gt; or &lt;code&gt;.rest&lt;/code&gt; file. The list of features it supports is impressive, you can use variables, chain calls together and build up a reference set of API calls which you can reuse and refer back to, or distribute with your code&lt;/p&gt;

&lt;p&gt;Get the extension here&lt;br&gt;
&lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=humao.rest-client&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Huachao" rel="noopener noreferrer"&gt;
        Huachao
      &lt;/a&gt; / &lt;a href="https://github.com/Huachao/vscode-restclient" rel="noopener noreferrer"&gt;
        vscode-restclient
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      REST Client Extension for Visual Studio Code
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Set up &amp;amp; Pre-reqs
&lt;/h1&gt;

&lt;p&gt;When calling any Azure API you clearly need to authenticate, to cut a VERY long story short, this means getting an access token.&lt;/p&gt;

&lt;p&gt;We'll use the common authentication scenario using a registered client, which is a &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow#request-an-access-token" rel="noopener noreferrer"&gt;Azure service principal plus the 'non-interactive flow' to request a token&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The REST extension can help us get this token. Yay.&lt;/p&gt;

&lt;p&gt;First create a &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal" rel="noopener noreferrer"&gt;service principal&lt;/a&gt; and give it the &lt;a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal" rel="noopener noreferrer"&gt;permissions to the Azure subscription&lt;/a&gt; you want to use.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file and place the service principal details into it, this lets us keep secrets out of source control (I mean, you have .env included in your &lt;code&gt;.gitignore&lt;/code&gt; of course)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;AZURE_SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"__YOUR_SUBSCRIPTION_ID__"&lt;/span&gt;
&lt;span class="nv"&gt;AZURE_TENANT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"__YOUR_TENANT_ID_ID__"&lt;/span&gt;
AZURE_CLIENT_ID&lt;span class="s2"&gt;"=__YOUR_CLIENT_ID__"&lt;/span&gt;
&lt;span class="nv"&gt;AZURE_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"__YOUR_CLIENT_SECRET__"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Requesting an Access Token
&lt;/h1&gt;

&lt;p&gt;In VS Code, create a new file with any name, but it should have &lt;code&gt;.http&lt;/code&gt; or &lt;code&gt;.rest&lt;/code&gt; as the file extension (like &lt;code&gt;azure-api.rest&lt;/code&gt;) this file extension is what activates the REST Extension for VS Code.&lt;/p&gt;

&lt;p&gt;Paste in the following contents&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;### Get access token to call Azure ARM API&lt;/span&gt;
&lt;span class="c1"&gt;# @name getToken &lt;/span&gt;
&lt;span class="s"&gt;POST https://login.microsoftonline.com/{{$dotenv %AZURE_TENANT_ID}}/oauth2/token&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/x-www-form-urlencoded&lt;/span&gt;

&lt;span class="s"&gt;grant_type=client_credentials&lt;/span&gt;
&lt;span class="nl"&gt;&amp;amp;resource&lt;/span&gt;&lt;span class="s"&gt;=https://management.azure.com/&lt;/span&gt;
&lt;span class="nl"&gt;&amp;amp;client_id&lt;/span&gt;&lt;span class="s"&gt;={{$dotenv %AZURE_CLIENT_ID}}&lt;/span&gt;
&lt;span class="nl"&gt;&amp;amp;client_secret&lt;/span&gt;&lt;span class="s"&gt;={{$dotenv %AZURE_CLIENT_SECRET}}&lt;/span&gt;

&lt;span class="c1"&gt;### Capture access token from getToken request&lt;/span&gt;
&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="s"&gt;authToken = {{getToken.response.body.access_token}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;{{$dotenv %FOO}}&lt;/code&gt; syntax is some of the magic in the REST extension to access variables from the &lt;code&gt;.env&lt;/code&gt; file&lt;/p&gt;

&lt;p&gt;A "Send Request" option should light up above the POST statement, click that to make the request and you should get a pane popup with the response containing the access token (and other details)&lt;/p&gt;

&lt;p&gt;It will store the access_token from the HTTP result into the &lt;code&gt;authToken&lt;/code&gt; variable, to be available to subsequent requests &lt;/p&gt;

&lt;h2&gt;
  
  
  Calling the Azure APIs
&lt;/h2&gt;

&lt;p&gt;Now you're set up to add more requests to the file and use the access token to call any Azure API&lt;/p&gt;

&lt;p&gt;For example to list all resource groups, paste the following after the code above. Note. The comment line starting with three hashes &lt;code&gt;###&lt;/code&gt; is important and what the REST extension uses to delimit requests. We plug the &lt;code&gt;authToken&lt;/code&gt; variable value into the Authorization header to authorise the request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;### List all storage accounts for subscription&lt;/span&gt;
&lt;span class="s"&gt;GET https://management.azure.com/subscriptions/{{$dotenv %AZURE_SUBSCRIPTION_ID}}/providers/Microsoft.Storage/storageAccounts?api-version=2019-06-01&lt;/span&gt;
&lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer {{authToken}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One again, hit "Send Request" just above the GET and you should get a reply from Azure listing all your resource groups. Neat!&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;The REST Client for VS Code makes authentication to call Azure APIs a simple and reusable task. Then calling those APIs can be easily set up without ever needing to leave your IDE&lt;/p&gt;

</description>
      <category>azure</category>
      <category>rest</category>
      <category>vscode</category>
      <category>api</category>
    </item>
  </channel>
</rss>
