Skip to content

posts🔗

Rebuild Dash Index Due to Corrupted Index

I use Dash for improved doc access. Terraform updated recently to 0.13.x and I began having odd issues with AWS provider results coming through. If you need to rollback, just go to the preferences and pick an older docset, in my case 0.13.0 worked correctly. Make sure to remove the problematic version (the uninstall refers to just the most recent, not any additional versions you selected under the dropdown)

If the index doesn't rebuild, you can close the app, manually remove the index, and it will rebuild on open. I'm pretty sure you don't need to do this if you use the uninstall option in the dialogue.

On macOS 10.15, you can find the index at ~/Library/Application Support/Dash/Data/manIndex.dsidx and delete this. Reopen Dash and it will rebuild the index.

Incredible setup experience with gitpod

What a polished setup experience from gitpod. Super impressed as I've never seen an interactive terraform setup asking for user input.

This basically generated an entire setup for GitPod, and persisted the Terraform plan for the entire stack it created in a directory for management and adjustments as desired.

I'm seriously impressed.

Check this out at: Install on AWS

# Setup Gitpod with self-setup docker installer
# https://www.gitpod.io/docs/self-hosted/latest/install/install-on-aws-script/
# Set-Location ./terraform/gitpod

Import-Module aws.tools.common, aws.tools.SecurityToken

Set-AWSCredential -ProfileName 'MyProfileName' -Scope Global

$ENV:AWS_ACCESS_KEY_ID = $cred.GetCredentials().AccessKey
$ENV:AWS_SECRET_ACCESS_KEY = $cred.GetCredentials().SecretKey
$ENV:AWS_DEFAULT_REGION = 'eu-west-1'

# can't use STS temporary credentials to create iam resources, so use normal iam credentials
docker run --rm -it -e AWS_ACCESS_KEY_ID=$ENV:AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$ENV:AWS_SECRET_ACCESS_KEY -e AWS_DEFAULT_REGION=$ENV:AWS_DEFAULT_REGION `
-v ${PWD}/awsinstall:/workspace eu.gcr.io/gitpod-io/self-hosted/installer:latest aws

Go R1 Day 5

Day 5 of 100

progress

  • I created my first unit test for go
  • It's a bit interesting coming from a background with PowerShell and Pester as my primary unit test framework. For instance, in Pester you'd declare the anything, but autodiscovery works with *.tests.ps1, being the normal convention.
  • There is no pointer value providing the test package, it's just other PowerShell calling PowerShell.
  • I'm biased I know, but the first test condition being like below seems clunky. I was hoping for something that was more like Pester with test.Equals(got, want,"Error message") as the syntax is more inline to what I'd expect. I haven't dived in further so this is just a thought, hoping this is just the newbie 101 test case example and there are more succinct comparison and test methods available.
package main

import "testing"

func TestHello(t *testing.T) {
    got := Hello()
    want := "Hello, world"
    if got != want {
        t.Errorf("got %q want %q", got, want)
    }
}
  • Update: 2020-08-24 2020-08-24
  • I'll stick with the default package while I'm learning. However, there is a package called Testify that is worth exploring if I find I still want assertions later on.

Go R1 Day 4

Day 4 of 100

progress

  • In the last week some more Pluralsight Go (Nigel's courses are always stellar)
  • I've done some odd work as had time in between last update, but nothing structured. Might continue with learn-go-with-tests but also came across exercism and might tackle that soon as well.
  • Setup new project in Visual Studio Codespaces
  • Used Serverless Framework to generate aws-go template project
  • Imported aws-go-sdk resources for AWS SSM Secrets Manager
  • Grabbed SSM Secrets manager output and used to create a POST request for authorization token
  • Used DumpRequest to pretty print output for debugging purpose
  • Hung my head in shame at my copy pasta project 😀
  • Realized half of the battle is just getting my lambda debugging effort running locally. Not exactly the easiest starter project.
  • Need to master different request types. PowerShell makes this easy with Invoke-RestMethod and object construction. I found that the Post method wasn't appropriate as I wanted to control custom headers. This required me to use a different approach, which I ended up doing with http.Client{}.
  • Not sure in a Go Playground sample to test and echo a post request. Thinking if no service that does this might try creating a Go routine to accept the request locally and echo for the purpose of a demo. Any suggestions welcome.
  • Identified i really need better understanding of the godoc libraries as would help a lot. Vscode intellisense even in codespaces isn't performing great, so I'm not getting that help that would really expedite discovery as a beginner. I might give my EAP Goland install a try and see if it helps.
  • Successfully included zap logging library
  • Successfully submitted request for authorization token and got response back into a struct, something that as a newbie I found a major win 🎉 using json.Unmarshal([]byte(body), ar) with ar referring to a pointer another win for me as new to pointers) being passed in like below:
// AuthResponse the authorization object returned by taco service when doing fancy things
type AuthResponse struct {
    MagicalToken string `json:"magical_token"`
    ExpiresIn    int    `json:"expires_in"`
}

func main() {
    var ar AuthResponse
    getToken(&ar) // pointer for the win ⚡️
}
func getToken(ar *AuthResponse) {
    json.Unmarshal([]byte(body), ar) // ❓ using bytes for json is new to me. gotta learn more
    sugar.Infow("Logging library with zap used to generate structured logs",
    "authResponse", ar,  // trailing quotes is the norm, also a new pattern for me
)
}

Go R1 Day 3

Day 3 of 100

progress

  • Learned about GOROOT, GOPATH and how to configure
  • Ran into problems with Visual Studio code reporting:
Failed to find the "go" binary in either GOROOT() or PATH(/usr/bin:/bin:/usr/sbin:/sbin. Check PATH, or Install Go and reload the window.
  • After attempting solution with various profile files, I tried setting the setting: "go.goroot": "/usr/local/opt/go/libexec/", in settings.json and this resolved the issue.
  • After it recognized this, I ran the Go: Current GOPATH from the command palette and it found it.
  • Finally, after this it reporting back some feedback showing it was recognizing the latest version I was running.
  • Initialized a new serverless framework project for aws-go-mod template using the following command: serverless create --template aws-go-mod --path ./sqlserver and the initial project layout was created.
  • I'm sure this will need to be improved as I go along, but since macOS failed on the go path setup, this resolved my problems for now.
# GO: Make tools work in console sessions
$ENV:GOPATH = "$ENV:HOME$($ENV:USERPROFILE)/go"

if ($PSVersionTable.OS -match 'Darwin') {
    $ENV:GOROOT = "/usr/local/opt/go/libexec"
    $ENV:PATH += "$ENV:PATH:$(go env GOPATH)/bin"
    $ENV:GOBIN = "$(go env GOPATH)/bin"
}

random-microsoft-teams-quirks-01

  • Using cmd+= results in zooming to 120%,145%,170%
  • Using cmd+- results in zooming out to 85%, 70%, 60%

How to Iterate Through A List of Objects with Terraform's for_each function

What I want to do

# create file local.users.yml
user:
  - name: foobar1
    email: foobar1@foobar.com
  - name: foobar2
    email: foobar2@foobar.com
  - name: foobar3
    email: foobar3@foobar.com
locals {
  users_file         = "local.users.yml"
  users_file_content = fileexists(local.users_file) ? file(local.users_file) : "NoSettingsFileFound: true"
  users_config       = yamldecode(local.users_file_content)
}

What I want to work:

resource "something" {
for_each local.users_config

name = each.key # or even each.value.name
email = each.value.email
}

What I've had to do

Now to iterate through this collection, I've had challenges, as the only way I've gotten this to work would be to ensure there was a designated key in the yaml structure. This provides a map object with a key/value format, instead of a collection of normal objects.

This would result in a yaml format like:

user:
  - 'foobar1':
      name: foobar1
      email: foobar1@foobar.com
  - 'foobar2':
       name: foobar2
       email: foobar2@foobar.com
  - 'foobar3':
       name: foobar3
       email: foobar3@foobar.com

This provides the "key" for each entry, allowing Terraform's engine to correctly identify the unique entry. This is important, as without a unique key to determine the resource a plan couldn't run in a deterministic manner by comparing correctly the previously created resource against the prospective plan.

Another Way Using Expressions

Iterating through a map has been the main way I've handled this, I finally ironed out how to use expressions with Terraform to allow an object list to be the source of a for_each operation. This makes feeding Terraform plans from yaml or other input much easier to work with.

Most of the examples I've seen confused the issue by focusing on very complex flattening or other steps. From this stack overflow answer, I experimented and finally got my expression to work with only a single line.

resource "foobar" "this" {
    for_each = {for user in local.users_config.users: user.name => user}
    name     = each.key
    email    = each.value.email
}

This results in a simple yaml object list being correctly turned into something Terraform can work with, as it defines the unique key in the expression.

simple conditional flag in terraform

Sometimes, you just need a very simple flag for enabled or disabled, or perhaps just a resource to deploy if var.stage == "qa". This works well for a single resource as well as collections if you provide the splat syntax.

resource "aws_ssm_association" "something_i_need_in_testing_only" {
   count = var.stage == "qa" ? 1 : 0
   name = var.name
}

grave accent

TIL: What I've been calling the backtick 👉 ```` 👈 for years, is technically the grave accent.