Mounting an EFS file system in ECS on AWS Fargate

Since April 2020 it’s now possible to mount an EFS file system from a task running on AWS Fargate.

There are some things you need to set up to make it work:

Security group

Ensure that the task can mount the EFS file system. For this you need allow access on port 2049. Edit this security group and add the relevant rule:
AWS EFS security group

Service platform

This one was a bit tricky. You have to choose version 1.4.0 of the service platform when creating the service. LATEST will not work!
AWS ECS service platform version

Mount the EFS file system

In the container section of your task definition you can mount the EFS file system.
AWS ECS task definition configuration

This results in the following JSON in the task definition:

"mountPoints": [
    {
      "readOnly": null,
      "containerPath": "/test/monkey",
      "sourceVolume": "<NAME>"
    }
],
"volumes": [
    {
      "efsVolumeConfiguration": {
        "transitEncryptionPort": null,
        "fileSystemId": "fs-f38e9d38",
        "authorizationConfig": {
          "iam": "DISABLED",
          "accessPointId": "fsap-00539689e5a4c9907"
        },
        "transitEncryption": "ENABLED",
        "rootDirectory": "/"
      },
      "name": "<NAME>",
      "host": null,
      "dockerVolumeConfiguration": null
    }
  ]

Solution for Samsung Galaxy S8+ not saving proxy settings on Android 9

So Samsung introduced a weird bug with the latest update – when you enter proxy settings for your wifi (e.g. your Charles instance) it looks like the settings are saved but they are not – when you go back into proxy settings it’s set to None again.

A workaround solution is to forget the wifi and connect to it again, this time entering proxy settings at the same time as the wifi password. If you need to clear / change proxy settings – do it again.

Hopefully Samsung fixes this rather annoying behaviour!

Generate POCOs.groovy – generate C# POCOs from table structure using JetBrains DataGrip

Use the Scripted Extensions menu available when right-clicking on a table in JetBrains DataGrip to run this script. It will then generate POCOs using the table structure. Save aa Generate POCOs.groovy.

import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil

/*
 * Available context bindings:
 *   SELECTION   Iterable<DasObject>
 *   PROJECT     project
 *   FILES       files helper
 */

packageName = "com.sample // TODO: change me!"
typeMapping = [
  (~/(?i)bit/)                          : "bool",
  (~/(?i)tinyint/)                      : "byte",
  (~/(?i)uniqueidentifier|uuid/)        : "Guid",
  (~/(?i)int|integer/)                  : "int",
  (~/(?i)bigint/)                       : "long",
  (~/(?i)char/)                         : "string",
  (~/(?i)varbinary|image/)              : "byte[]",
  (~/(?i)double|float|real/)            : "double",
  (~/(?i)decimal|money|numeric|smallmoney/)       : "decimal",
  (~/(?i)datetime|datetime2|timestamp|date|time/) : "DateTime",
  (~/(?i)datetimeoffset/)                         : "DateTimeOffset",
  (~/(?i)/)                                       : "String"
]

FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
  SELECTION.filter { it instanceof DasTable && it.getKind() == ObjectKind.TABLE }.each { generate(it, dir) }
}

def generate(table, dir) {
  def className = csName(table.getName())
  def fields = calcFields(table)
  new File(dir, className + ".cs").withPrintWriter { out -> generate(out, className, fields) }
}

def generate(out, className, fields) {
  out.println "using System;"
  out.println ""
  out.println "namespace $packageName"
  out.println "{"
  out.println "\tpublic class $className"
  out.println "\t{"
  fields.each() {
    out.println "\t\tpublic ${it.type} ${it.name.capitalize()} { get; set; }"
  }
  out.println "\t}"
  out.println "}"
}

def calcFields(table) {
  DasUtil.getColumns(table).reduce([]) { fields, col ->
    def spec = Case.LOWER.apply(col.getDataType().getSpecification())
    def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
    fields += [[
                 name : csName(col.getName()),
                 type : typeStr,
                 annos: ""]]
  }
}

def csName(str) {
  str.replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
}

Indenting code in Visual Studio Code with VSCodeVim plugin

Here is the configuration I use for VSCodeVim to enable using Tab and Shift-Tab to indent and unindent code in normal and visual modes.

"vim.otherModesKeyBindingsNonRecursive": 
[
    {
        "before": ["S-Tab"],
        "after": [],
        "commands": [
            {
                "command": "editor.action.outdentLines",
                "args": []
            }
        ]
    },
    {
        "before": ["Tab"],
        "after": [],
        "commands": [
            {
                "command": "editor.action.indentLines",
                "args": []
            }
        ]
    }
]

Bash script to rename files given a text file with new filenames

Yesterday I found myself needing to rename a bunch of files given a text file with the new names, so I had to use some of my (few) bash skills. I’m sure I could have done it in fewer lines, but the bash script below did the job.

#!/bin/bash

# v1.1
# USAGE:
# ./rename.sh text.txt *.dat

if [ "$#" == "0" ]; then
    echo "./rename.sh names.txt \"*.dat\""
    exit 1
fi

namefile=$1
shift

# read file line by line, store in array with leading number and .dat postfix
index=0
while read line; do
	fileNum=`printf "%02d" $((index+1))`
	names[index]="$fileNum. $line.dat" # Custom rename format
	((++index))
done < $namefile

namecount=${#names[@]}

if [ "$#" -ne "$namecount" ]; then
	echo "Number of files ($#) doesn't match number of lines in $namefile ($namecount)"
	exit 1
fi

# rename input files to match lines in the array
index=0
files=("$@")
for file in "${files[@]}" ; do
	file=$(printf "%q" "$file")
	newfile=$(printf "%q" "${names[index]}")
	eval "mv $file $newfile"
  	((++index))
done

ComHem TivoToGo krashar på iPad – lösning

This one is in Swedish, but if your TiVo app crashes when used to control your TiVo box – use Google translate to read the text below.

Sedan en tid tillbaka har TivoToGo börjaat krasha direkt vid start på min iPad. Efter ett fruktlöst samtal med ComHems support bestämde jag mig för att spåra ner problemet.

Det första jag märkte var att appen bara krashade när iPaden är ansluten till samma wifi som Tivo-boxen, om jag stängde av wifi på iPaden och startade på 3G så funkade appen. Jag kunde dock givetvis inte styra boxen vilket är en del av appens poäng.

Så appen och boxen pratar på något sätt, antingen direkt eller via ComHem. Jag bestämde mig för att ta reda på det och kickade igång WireShark. För att inte bråka med inställningarna för krypteringsnycklar tog jag bort lösenordet på min wifi access point… och VIPS så började appen funka och styra boxen! Märkligt! Jag satte tillbaka samma lösenord – crash igen. Tog bort lösenordet – funkar! Satte ett nytt lösenord – FUNKAR! Wtf?

Har inte orkat kolla noggrant men det såg inte heller ut som att det gick trafik mellan boxen och appen, kommunikationen verkar ske via ComHem. Använder de möjligen krypteringsnycklarna för det wifi iPaden är på för att identifiera ens nät? ComHem – kommentar? =)

Hur som helst, jag är för lat för att undersöka detta vidare, enda uppsidan skulle ju vara att kunna styra TiVon från ett annat LAN, inget jag är jätteintresserad av. Kontentan är:

OM DIN TIVO APP PÅ DIN IPAD CRASHAR NÄR DEN ÄR PÅ SAMMA NÄT SOM DIN COMHEM TIVO-BOX – BYT LÖSENORDET PÅ DIN WIFI!

Karabiner Num Lock to Eject

Put this in your private.xml to remap Num Lock to Eject on your Mac running OSX

<?xml version="1.0"?>
<root>
  <item>
  <name>Richard</name>
  <list>
  <item>
    <name>Map NumLock to Eject</name>
    <identifier>private.swap_NumLock-to-Eject</identifier>
    <autogen>--KeyToKey-- KeyCode::PC_KEYPAD_NUMLOCK, KeyCode::VK_CONSUMERKEY_EJECT</autogen>
  </item>
  </list>
  </item>
</root>

Fix for AuthManager(CommerceServer): Error reading Commerce Server administration database

The below exception is easily remedied by removing all entries that relate to Commerce Server authentication module from your web.config. You are probably not using that module. 🙂

[COMException (0x800a0cc1): AuthManager(CommerceServer): Error reading Commerce Server administration database. Check the AddressKeyName setting in the CSApp.ini file for the site and ensure that it refers to the name of a Commerce Server application that exists for the site. Site name: 'MySite' Application name: 'MySite' Auth resource property: 's_SecureHostname' HRESULT: 0x800A0CC1]