Today I Learned

15 posts by bartłomiejwójtowicz

Terraform AWS - moving state to another module

If your infrastructure grows and you find that certain resources should be moved to its own module because they need to be shared with others (or you made a mistake by putting them in the wrong module in the first place), you can move the state using CLI rather than recreating resources from scratch.

let’s say you have:

module "s3" {
  source = "./modules/s3"
  ...
}

and inside you defined user with access policy:

resource "aws_iam_user" "portal" {...}

resource "aws_iam_user_policy" "portal" {...}

Use:

terraform state mv module.s3.aws_iam_user.portal  module.iam
terraform state mv module.s3.aws_iam_user_policy.portal  module.iam

After that you can move your resource definitions from s3 to iam module. At the end, run terraform plan - terraform shouldn’t detect any changes.

Documentation here.

Rake / rails console does not work in docker?

When using default ruby image in your Dockerfile (FROM ruby:2.5.1) if you encounter any problems with missing gems in your container when running rake task or rails console:

Could not find rake-x.y.z in any of the sources. Run bundle install to install missing gems.

That’s because you probably used:

RUN bundle install --deployment

You can fix it with:

RUN bundle install --without development test

Downgrading Heroku PG database

Accidentally I’ve provisioned paid plan for PG database. To downgrade such a database you need to:

# safety measures
heroku maintenance:on

# create a new database, new url will be given, for me it was: HEROKU_POSTGRESQL_ORANGE_URL
heroku addons:create heroku-postgresql:hobby-dev 

 # copy current db to ORANGE db
heroku pg:copy DATABASE_URL HEROKU_POSTGRESQL_ORANGE_URL

# make new database active
heroku pg:promote HEROKU_POSTGRESQL_ORANGE_URL

# ... and we are back
heroku maintenance:off

After promotion old database was renamed to PINK then I removed it from heroku panel.

There is also other strategy for downgrade but it does not work for free plan: docs

Simplifying Circle CI setup for Crystal

Rather than setting up test environment for Crystal by yourself you can use official docker image:

version: 2
jobs:
  build:
    docker:
      - image: crystallang/crystal:0.25.0
    steps:
      - checkout

      - restore_cache:
          keys:
            - shards-{{ checksum "shard.lock" }}
      - run:
          name: Install shards
          command: |
            shards check || shards
      - save_cache:
          key: shards-{{ checksum "shard.lock" }}
          paths:
            - lib/
            - .shards/

      - run:
          name: Run specs
          command: crystal spec

Using mocks library in Crystal

Mocks cannot be defined in describe/it body so this won’t work:

describe Bot::Slack do
  describe "#post_response" do
    it "sends formatted message" do
      Mocks.create_mock JsonClient do
        mock self.post(url, body)
      end
      # testing here

and you will get: can't declare class dynamically.

Correct way:

Mocks.create_mock JsonClient do
  mock self.post(url, body)
end

describe Bot::Slack do
  describe "#post_response" do
    it "sends formatted message" do
      # testing here

Custom validation error messages when using forms

Normally for rails model (i.e. Brand) you would do:

en:
  activerecord:
    errors:
      models:
        brand:
          attributes:
            subdomain:
              invalid: "should contain only 'a-z', '0-9' or '-' but not as starting or ending character"

When using validations in forms you need a small tweak:

  • activerecord => activemodel
  • brand => brand_form (assuming your form is BrandForm)

Final translation:

en:
  activemodel:
    errors:
      models:
        brand_form:
          attributes:
            subdomain:
              invalid: "should contain only 'a-z', '0-9' or '-' but not as starting or ending character"

Note: invalid is the key for validation type, full list here