Showing posts with label infrastructure as code. Show all posts
Showing posts with label infrastructure as code. Show all posts

December 12, 2021

Day 12 - Terraform Refactoring

By: Bill O'Neill (@woneill)
Edited by: Kerim Satirli (@ksatirli)

Terraform is "Infrastructure as Code" and like all code, it is beneficial to review and refactor to:

  • improve code readability and reduce complexity
  • improve the maintainability of the source code
  • create a simpler, cleaner, and more expressive internal architecture or object model to improve extensibility

This article outlines the approaches that have helped my teams when refactoring Terraform code bases.

Convert modules to independent Git repositories

If your Terraform Git repository has grown organically, you will likely have a monorepo structure complete with embedded modules, similar to this:

$ tree terraform-monorepo/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── ...
├── modules/
│   ├── moduleA/
│   │   ├── README.md
│   │   ├── variables.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   ├── moduleB/
│   ├── .../

Encapsulating resources within modules is a great step, but the monorepo structure makes it difficult to iterate on individual module development, down the line.

Splitting the modules into independent Git repositories will:

  • Enable module development in an isolated manner
  • Support re-use of module logic in other Terraform code bases, across your organization
  • Enable publishing to public and private Terraform Registries

Here's a process that you can follow to make a module a stand-alone Git repository while preserving the historical log messages. The steps are examples of how to extract moduleA from the above file tree into its own git repository.

  1. Clone the Terraform Git repository to a new directory. I recommend naming the directory after the module you plan on converting.
    git clone <REMOTE_URL> moduleA
  2. Change into the new directory:
    cd moduleA
  3. Use git filter-branch to split out the module into a new repository..
    FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --subdirectory-filter modules/moduleA -- --all

    Note that we're squelching the warning about filter-branch. See the filter-branch manual page for more details if you're interested

  4. Now your directory will only contain the contents of the module itself, while still having access to the full Git history.

    You can run git log to confirm this.
  5. Create a new Git repository and obtain the remote URL for it, then update the origin in the filtered repository:
    git remote set-url origin <NEW_REMOTE_URL>
    git push -u origin main
    
  6. Tag the repo as v1.0.0 before making any changes

       
    git tag v1.0.0
    git push --tags
    
  7. Now that the new repository is ready to be used, update the existing references to the module to use a source argument that points to the tag that you just created.

    The “Generic Git Repository” section in Terraform's Module Sources documentation has more details on the format.

    Replace lines such as

    source = "../modules/moduleA"


    with

    source = "git::<NEW_REMOTE_URL>?ref=v1.0.0"
    
  8. Alternatively, publishing your module to a Terraform registry is an option (but this is outside the scope of this article).
  9. Once all source arguments that previously pointed to the directory path have been replaced with references to Git repositories or Terraform registry references, delete the directory-based module in the original Terraform repository.

Update version constraints with tfupdate

Masayuki Morita's tfupdate utility can be used to recursively update version constraints of Terraform core, providers, and modules.

As you start refactoring modules and bumping their version tags, tfupdate becomes an invaluable tool to ensure all references have been updated.

Some examples of tfupdate usage, assuming the current directory is to be updated:

  • Updating the version of Terraform core:
    tfupdate terraform --version 1.0.11 --recursive .
  • Updating the version of the Google Terraform provider:
    tfupdate provider google --version 4.3.0 --recursive .
  • Updating the version references of Git-based module sources can be done with the module subcommand, for example:
    tfupdate module git::<REMOTE_URL> --version 1.0.1 --recursive .

Test state migrations with tfmigrate

Many Terraform users are hesitant to refactor their code base, since changes can require updates to the state configuration. Manually updating the state in a safe way involves duplicating the state, updating it locally, then copying it back in place.

In addition to tfupdate, Masayuki Morita has another excellent utility that can be used to apply Terraform state operations in a declarative way while validating the changes, before committing them: tfmigrate

You can do a dry run migration where you simulate state operations with a temporary local state file and check to see if terraform plan has no changes after the migration., This workflow is safe and non-disruptive, as it does not actually update the remote state.

If the dry run migration looks good, you can use tfmigrate to apply the state operations in a single transaction instead of multiple, individual changes.

Migrations are written in HCL and use the following format:

migration "state" "test" {
  dir = "."
  actions = [
    "mv google_storage_backup.stage-backups google_storage_backup.stage_backups",
    "mv google_storage_backup.prod-backups google_storage_backup.prod_backups",
  ]
}

Each action line is functionally identical to the command you’d run manually such as terraform state <action> …. A full list of possible actions is available on the tfmigrate website.

Quoting resources that have indexed keys can be tricky. The best approach appears to be using a single quote around the entire resource and then escaping the double quotes in the index. For example:

actions = [
    "mv docker_container.nginx 'docker_container.nginx[\"This is an example\"]'",
]

Testing the state migrations can be done via tfmigrate plan <filename>. The output will show you what terraform plan would look like if you had actually carried out the state changes.

Applying the migration to the actual state is done via terraform apply <filename>. Note that by default, it will only apply the changes if the result from tfmigrate plan was a clean output.

If you still want to apply changes to a “dirty” state, you can do so by adding a force = true line to the migration file.

If you are using Terraform 1.1 or newer, there is now a built-in moved statement that works similarly to these approaches. I haven’t tested it out yet but it looks like a useful feature! I can see it being especially useful for users who may not have direct access to state files such as Terraform Cloud and Enterprise users or Atlantis users.

See the announcement in the 1.1 release as well the HashiCorp Learn tutorial for more details.

Ensure standards compliance with TFLint

According to its website, TFLint is a Terraform linter with a handful of key features:

  • Finding possible errors (like illegal instance types) for major Cloud providers (AWS/Azure/GCP)
  • Warning about deprecated syntax and unused declarations
  • Enforcing best practices and naming conventions

TFLint has a plugin system for including cloud provider-specific linting rules as well as updated Terraform rules. Setting up the list of rules can be done on the command line but it is recommended to use a config file to manage the extensive list of rules to apply to your codebase.

Here is a configuration file that enables all of the possible terraform rules as well as includes AWS specific rules. Save it in the root of your Git repository as .tflint.hcl then initialize TFLint by running tflint –init. Now you can lint your codebase by running tflint

config {
  module              = false
  disabled_by_default = true
}

plugin "aws" {
  enabled = true
  version = "0.10.1"
  source  = "github.com/terraform-linters/tflint-ruleset-aws"
}

rule "terraform_comment_syntax" {
  enabled = true
}

rule "terraform_deprecated_index" {
  enabled = true
}

rule "terraform_deprecated_interpolation" {
  enabled = true
}

rule "terraform_documented_outputs" {
  enabled = true
}

rule "terraform_documented_variables" {
  enabled = true
}

rule "terraform_module_pinned_source" {
  enabled = true
}

rule "terraform_module_version" {
  enabled = true
  exact = false # default
}

rule "terraform_naming_convention" {
  enabled = true
}

rule "terraform_required_providers" {
  enabled = true
}

rule "terraform_required_version" {
  enabled = true
}

rule "terraform_standard_module_structure" {
  enabled = true
}

rule "terraform_typed_variables" {
  enabled = true
}

rule "terraform_unused_declarations" {
  enabled = true
}

rule "terraform_unused_required_providers" {
  enabled = true
}

rule "terraform_workspace_remote" {
  enabled = true
}

pre-commit

Setting up git hooks with the pre-commit framework allows you to automatically run TFLint, as well as many other Terraform code checks, prior to any commit.

Here is a sample .pre-commit-config.yaml that combines Anton Babenko's excellent collection of Terraform specific hooks with some out-of-the-box hooks for pre-commit. It ensures that your Terraform commits are:

  1. Following the canonical format and style per terraform fmt
  2. Syntactically valid and internally consistent per terraform validate
  3. Passing TFLint rules
  4. Ensuring that good practices are followed such as:
    • merge conflicts are resolved
    • private ssh keys aren't included
    • commits are done to a branch instead of directly to master or main
repos:
  - repo: git://github.com/antonbabenko/pre-commit-terraform
    rev: v1.59.0
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_tflint
        args:
          - '--args=--config=__GIT_WORKING_DIR__/.tflint.hcl'
  - repo: git://github.com/pre-commit/pre-commit-hooks
    rev: v4.0.1
    hooks:
      - id: check-added-large-files
      - id: check-merge-conflict
      - id: check-vcs-permalinks
      - id: check-yaml
      - id: detect-private-key
      - id: end-of-file-fixer
      - id: no-commit-to-branch
      - id: trailing-whitespace

You can take advantage of this configuration by:

  • Installing the pre-commit framework per the instructions on the website.
  • Creating the above configuration in the root directory of your Git repository as .pre-commit-config.yaml
  • Creating a .tflint.hcl in the base directory of the repository
  • Initialize the pre-commit hooks by running pre-commit install

Now whenever you create a commit, the hooks will run against any changed files and report back issues.

Since the pre-commit framework normally only runs against changed files, it’s a good idea to start off by validating all files in the repository by running pre-commit run –all-files

Conclusion

These approaches help make it easier and safer to refactor Terraform codebases, speeding up a team's "Infrastructure as Code" velocity.

This helped my team gain confidence in making changes to our legacy modules and enabled greater reusability. Standardizing on formatting and validation checks also sped up code reviews. We could focus on module logic instead of looking for typos or broken syntax

December 1, 2021

Day 1 - The Myths and the Magic in My Search for Acquiring Software Engineering Skills

By: Annie Hedgpeth (@anniehedgie)
Edited by: Jennifer Davis (@sigje)

A happy SysAdvent to you, my dear elves. Whether you are an individual contributor (IC), manager, director, or something in between, my holiday wish is that my story spreads some holiday magic to your teams and roadmap.

“Then I traveled through the seven levels of the Candy Cane forest, past the sea of twirly-swirly gumdrops, and then I walked through the Lincoln Tunnel.” Buddy the Elf

I took an uncommon route into technology. With absolutely no experience of any kind in any sort of technological pursuit (save for video editing in college), I started my career in IT by learning configuration management and infrastructure as code first. Why? Because the opportunity presented itself, and I had a great in-house tutor. My husband, Michael, is the one who convinced me to pursue a career in technology and was the one who spent many late evenings teaching me how to “computer”. It was a bit of a trek through “the seven levels of the Candy Cane forest, through the sea of swirly twirly gumdrops” but with more tears and heartache.

I spent the first couple of years of my career just trying to learn enough of the different frameworks, like Chef, Terraform, PowerShell, Groovy, etc., to build stuff and configure it properly. Learning about how they should be built and configured came next with a focus on solution architecture and a bit on systems administration. Looking forward, after five years of work focused on configuration management, infrastructure as code, and CI/CD pipelines, I’m now to the point where I want to grow in software engineering, and this is where our story of myths and magic begins today.

“Some call it ‘the show’ or ‘the big dance’; it’s the profession that every elf aspires to…” – Papa Elf

Grab some hot cocoa and curl up with a blanket while I share with you what I see as the common myths believed about acquiring software engineering skills and what I believe to be the actual magic of making that a reality in my life. We will start with the myths, but please remember, dear elves, that these are myths and magic as they pertain to me personally. For you or others, they may not be, and that’s okay. My hope is that sharing my own experiences will give you empathy for others on their unique journeys and/or compassion for yourself as you learn and grow in your own way.

“The best way to spread Christmas cheer is singing loud for all to hear.” – Buddy the Elf

Myth #1 - Just read a book

I am a huge fan of books, and I consume a pretty good amount of books per year. I think that learning through books is important in a way that is difficult to replicate through other modalities. I have gone through Head First Go, a book that is geared toward people with little to no programming experience, and I found it to be incredibly helpful. I did every exercise in the book, learned a lot, and highly recommend it. That said, the exercises alone were not enough to prepare me immediately for real life coding. Doing the exercises was good and necessary, but it was only one piece of the puzzle required to complete the picture of what it takes for me to be able to contribute in a meaningful way to my company’s Go codebase.

Perhaps my lack of any formal training, whether university or code camp, prevented me from grasping the higher level understanding that would have enabled me to contribute confidently sooner, but whatever it was, I was still lacking after simply going through a book. I liken this to studying through a first year French textbook as your only means of learning the language. You will gather the concepts and vocabulary, but you will likely not be able to speak the language without other mediums of instruction.

Myth #2 - Just do some exercises

I am a huge fan of Exercism. I think they are helping a lot of people learn coding languages, and they do it in such a way that brings out a spirit of giving back in its users. There is much to love about that. I have completed many Exercism exercises, and I do find them helpful, but in the same way that the book was only helpful to a certain point, I haven’t found that it helps me with the big picture. I have found it to be like learning French with only Duolingo. Sure it’s a great app, and I use it all the time. But again, one cannot use it in isolation in order to be a proficient French speaker.

Myth #3 - Solution Architecture skills are built upon coding skills

Working at a cloud consulting firm for 4 years, I got a great education in architecting solutions for clients. I really enjoyed learning about the process, and it all made a lot of sense to me. After seeing several of them, I started to see the patterns and practices that are used to create a good solution. And then, as the person often implementing someone else’s solution, I learned quickly what made a bad solution, as well.

To be good at architecting solutions, one must think through all of the choices required to form that solution while you’re still in the planning phase, before any of the solution is actually implemented. You can’t really “mess around and find out”, which is why solutions architecture is such a valuable skill; if you plan well, you do the necessary work, no less and no more.

However, not all solutions are equal. Architecting a solution to a cloud migration feels like more of a tactile experience to me; I can see where things are moving. I think it helps that you can actually hold a CPU in your hands, and an architectural diagram has a very structural feel to it, similar to a blueprint of physical structures. For me, at least, this makes it more accessible and the concepts easier to grasp.

However, software architecture is more conceptual. You have to first understand all of the interfaces, levels of abstraction, and concepts before you can understand how to architect it. And if you don’t understand how to architect it, then you’re back at the Duolingo level of coding.

Myth #4 - The building blocks to starting a tech career are cloud, code editor, source control, and project management

Some people have suggested that huge barriers to moving into a software engineering role can be mastering the tooling - code editors and IDEs, source control, the cloud providers, and project management. This is possibly true of a certain type of person moving from a systems administration type of job into software development, but this was not true for me. But because Michael worried that these would be barriers for me, I learned them first. I created a website with GitHub Pages and used that as a way to learn source control and Visual Studio Code. I took some online classes on Agile Framework. I got a free Azure account and started playing with Terraform. These things were most definitely and obviously important, but again, they’re but one piece of the puzzle.

Myth #5 - It just takes a creativity / growth / problem-solving mindset

One of my husband’s main reasons for convincing me to pursue a career in tech was that I’m a pretty creative person who loves problem solving and that the desire to dig into a problem until it’s solved is one of the most necessary components for a career in tech. I completely agree that this is an important character trait in order to be successful as a technologist. I’m also decently creative and have a growth mindset, which are equally valuable for such a pursuit. You can probably see, by now, where I’m going with this, though.

These traits alone are great and will serve you well in just about any endeavor. Having these traits does not make a person automatically good at tech. It’s like when you’re house-hunting and find a house that needs a ton of cosmetic remodeling, but you say, “It has good bones,” meaning, you can easily make it the way you want it to look without having to overhaul anything structurally. Still, though, the cosmetic renovations are not insignificant. They are a lot of work.

The same is true with me. Yes, I have “good bones” - good traits that are great assets for a career in tech, like being creative, having a growth mindset, and being a good problem solver. But to let folks start a career in tech with the false hope that these traits will give them an unrealistic advantage is not helpful. Yes, those traits help me a lot, but, goodness me, it is still a lot of work learning and growing in tech, even with those traits.

Real barriers:

Truth #1 - People get pigeon-holed into certain work

I worked so hard to get the skills necessary to be valuable to my respective organizations, and while, yes, I found myself a bit pigeon-holed into “devops-y” roles, the other truth is that I didn’t feel as experienced as my peers because I didn’t have the formal training many of them had, so I felt behind in my learning. I wanted to catch up to the folks my age in this business, and that was nearly impossible, so the next best thing was to get really good at one thing, and just like that, I found myself pigeon-holed. This was honestly probably easier and less risky for the companies I was in as things were more predictable and steady when I was more focused on a smaller scope of expertise. And you might be thinking, ‘So what’s the problem with striving to become a subject matter expert at something. There’s immense value in that.’ And you’d be right. This is perfectly fine for some people. However, I personally like to have a range in my work. I find freedom in flexibility as my hope is that it gives me more options in my future, ultimately decreasing the risk to my career.

“There’s room for everyone on the Nice list.” Buddy the Elf

To overcome the barrier of being pigeon-holed into a particular line of work, a bit of magic is required - the magic that happens when goals are set and people help other people. Setting goals and tracking them is extremely important to me, but part of tracking those goals is being accountable to them by someone, whether it be a manager, a mentor, or a team lead. When my manager or team leads know my goals and I have milestones set for reaching those goals, then I am so much more likely to achieve them, and I’m giving them an opportunity to play an important role, which grows their leadership skills - a win-win.

Truth #2 - It’s an engineering problem for senior engineers to break down work to share work with juniors

My favorite type of senior engineer is one who can not only design a good solution but one who knows how to allow everyone on the team to contribute to the solution with their own strengths. Being able to communicate their vision for a solution to others and lead others effectively to carry out their vision is arguably the most valuable skill of a senior engineer. The whole team thrives when seniors lead in this way! Being able to do this is most definitely classified as a soft skill - one that is not easily measured by a test, and I have witnessed many ICs discount soft skills, thinking that only managers need worry themselves with growing such skills. I would argue, though, that this particular soft skill is also an engineering skill, one necessary to be an effective IC engineer.

“I mean, parents couldn’t do that all in one night.” Buddy the Elf

Conversely, how many times have you seen senior engineers go silent for two months and then emerge with an amazing something that solves a problem, but it resembles a coded version of a complicated Home Alone trap (like a Rube Goldberg machine)? This is actually not what we want from our senior engineers, dear elves. We want senior engineers who are able to thoughtfully and skillfully level up those in lower levels to them.

There is a common desire among engineers to remain as IC for as long as possible with no desire for the managerial track, and that is totally fine! However, being an IC does not mean that you work within a vacuum. No matter your level, every IC can have a positive influence on someone else on the team and can bring leadership and mentorship into their everyday roles. Seniors, however, have the responsibility to give others the opportunity to contribute to their vision. By considering the other people on their team and their strengths and goals, solutions can be designed so that everyone grows. Is it hard? Of course! But when it happens, it’s like magic.

I started my career in tech a few days before I turned 37, so with the amount of catch-up I have from being late to the game, I just need help sometimes. An hour of help from a human being, for me at least, is the absolute most supercharged way to learn. I am so grateful to have had people all throughout my time in tech who understand that investing in people by pairing on a problem is really an investment in the health and wellness of the team, product, and company. I would argue also that it makes them a better person, teacher, and leader.

I wholeheartedly believe that fostering this environment should be the number 1 priority of every engineering manager because it will solve a lot of other problems down the line naturally. We need not be islands unto ourselves but rather a rising tide that lifts all ships.

Truth #3 - A team needs dedicated time to grow

Getting time to grow at a consultancy was tough. It was usually designated to times when I was on the bench, but that time wasn’t consistent. There were times where I would go an entire year or more with no bench time, so I had to use my personal time. I will take this time to remind you, dear elves, that making your employees use their personal time for growth and development is not an inclusive practice. It makes it harder for folks with families, disabilities, or just plain healthy boundaries to have the time and space to learn.

“I planned out our whole day. First we make snow angels for two hours, and then we’ll go ice skating, and then we’ll eat a whole roll of Tollhouse Cookie Dough as fast as we can, and then to finish, we’ll snuggle.” Buddy the Elf

I’m so incredibly grateful for my current manager and team who have deemed half a day on Fridays to be dedicated learning times. When we all have learning time at the same time, then no one feels guilty for not working on sprint work because, as a team, we’ve decided that learning is important enough to spend time on it. I’ve gotten a lot out of this; I finished the aforementioned Head First Go book, and I’ve worked on Exercism exercises. I’ve also used it to learn how to do things that were blocking me in my sprint work. But to make the most out of this time, my next step is to use Friday learning times to actually use the things I’ve learned in real world work. This, however, may exceed the bounds of half a day on Fridays, and it may mean that I take a bug fix ticket and spend a whole week on it. The magic required is that the team and manager buy into this investment of time and energy. I personally know that I would get that buy-in on my current team, but I know I’m a lucky one. They know that the payoff of me growing my skills is worth the investment of time.

Truth #4 - Insecurity looms with the lack of formal education through a coding school OR engineering degree which makes it feel more difficult to acquire certain skills

This might be an unpopular opinion, and I just stated it as a truth, but I do believe that this is true for me. There are certain coding exercises that I have tried that make me feel like I will never truly understand certain concepts. I do believe that I will know enough to be valuable, but knowing when that matters and when it doesn’t is a mind trip. It’s difficult to manage my own expectations of my own growth, learning, and knowledge. The constant nagging thought in the back of my head is that if I would have had any sort of formal coding training, whether in university or code camp, that something would have clicked in my brain so that I understood certain concepts more quickly, and I honestly don’t know if this is a valid concern for me or not.

I do know that magic happens when people step in. When I have brilliant developer people in my life telling me what matters and what doesn’t matter and helping me to grasp fundamental concepts, my growth and confidence are accelerated greatly. I go from focusing on my blockers to focusing on my trajectory.

“Oh, it’s not a costume. I’m an elf. Well, technically, I’m a human, but I was raised by elves.” Buddy the Elf

Truth #5 - Career planning related to skills is a bit more complicated

When you’re a career-changer and are late to the tech game, planning for the future can be a bit complicated. My current difficulty is that I have the soft skills required to be a really great manager, but managing a technical team requires a great depth of knowledge that only comes with experience. So what do I do with all of this leadership potential? For now, I’m doing nothing. I’m growing my depth and breadth, hunkering down and growing, and that’s so frustrating!

But again, therein lies the potential for magic. If a manager and a team are intentional about growing people to their own strengths and goals, then we can carve a path that matches my goals and strengths with the business’s needs, but it requires a bit of creativity and flexibility. It takes mature leadership to know how to turn each team member’s potential into something that benefits everyone.

“I just like smiling. Smiling’s my favorite.” Buddy the Elf

TL;DR

Did you note a common thread? The myths I outlined are discouraging blockers that kept me from thinking that I could achieve my goals, and I have a hunch that I’m not alone in these feelings. But the magic lies in people caring about and investing in each other’s growth. That’s it! This is not just the kind, empathetic, and right thing to do, but it also will affect the business’s bottom line because when people are more committed to growth and feel encouraged to do so, they are creating quality products and they are staying put in the same place longer because they feel supported. As you go about your holiday and new year, I encourage you to bring a little bit of magic to your own teams by either being the support someone needs or by allowing someone to be a support for you.

“Bye Buddy, hope you find your dad!” – Mr. Narwhal