How to make AWS CLI commands easy to run with generate-cli-skeleton

Some CLI commands have a few compulsory parameters and/or require complex values (JSON objects or arrays). Typing these commands to the terminal can be cumbersome and can lead to typos. In this post, I'll show you a CLI parameter that makes the execution of these commands easier.

Using the AWS CLI is very useful because it helps you see how each service or command works and increases your chances to pass AWS certification exams.

Often times though the CLI command is quite cumbersome: you would need to write JSON-format in the command line or there are simply just too many parameters involved for the specific command.

This will increase that probability of me making a typo somewhere in the four-line command and then I’ll spend a few seconds (minutes) debugging what causes the error message.

1. Use help

I can definitely use help.

Each command comes with a help section. It can be brought up like this:

aws dynamodb create-table help

Please note that unlike many other CLI commands, there is no -- before help.

This will bring up the same help section that you can find in the CLI page of the relevant service. For DynamoDB CreateTable, this page will be displayed to the console. It’s the same document as I’d read in the browser.

Unfortunately, using the help parameter doesn’t prevent me from writing long commands.

1. generate-cli-skeleton

There is a cool feature that I started to use to reduce the number of these cases. It’s called generate-cli-skeleton.

This command will return a JSON object with all available parameters. I can write the content of the response to a JSON file and now I’ll have the template for the command.

I can then edit the JSON in the editor of my choice, remove the parameters I don’t need and add the values to the ones I do need.

2. Example

I’ll create a DynamoDB table and add an item to it using the generate-cli-skeleton parameter. This is a very common task and DynamoDB’s CLI commands can be quite complex.

The table will be called Pets and I will upload an item (a pet) to the table.

2.1. Create the table

Let’s start with saving the CreateTable template:

aws dynamodb create-table --generate-cli-skeleton > create-table.json

A file called create-table.json will be created in the folder from where the command was run. The content of the file looks like this:

{
  "AttributeDefinitions": [
    {
      "AttributeName": "",
      "AttributeType": "N"
    }
  ],
  "TableName": "",
  "KeySchema": [
    {
      "AttributeName": "",
      "KeyType": "RANGE"
    }
  ],
  "LocalSecondaryIndexes": [
    {
      "IndexName": "",
      "KeySchema": [
        {
          "AttributeName": "",
          "KeyType": "RANGE"
        }
      ],
      "Projection": {
        "ProjectionType": "ALL",
        "NonKeyAttributes": [
          ""
        ]
      }
    }
  ],
  "GlobalSecondaryIndexes": [
    {
      "IndexName": "",
      "KeySchema": [
        {
          "AttributeName": "",
          "KeyType": "RANGE"
        }
      ],
      "Projection": {
        "ProjectionType": "KEYS_ONLY",
        "NonKeyAttributes": [
          ""
        ]
      },
      "ProvisionedThroughput": {
        "ReadCapacityUnits": 0,
        "WriteCapacityUnits": 0
      }
    }
  ],
  "BillingMode": "PROVISIONED",
  "ProvisionedThroughput": {
    "ReadCapacityUnits": 0,
    "WriteCapacityUnits": 0
  },
  "StreamSpecification": {
    "StreamEnabled": true,
    "StreamViewType": "NEW_IMAGE"
  },
  "SSESpecification": {
    "Enabled": true,
    "SSEType": "AES256",
    "KMSMasterKeyId": ""
  },
  "Tags": [
    {
      "Key": "",
      "Value": ""
    }
  ]
}

The JSON proves that create-table is a command that is difficult to submit from the CLI: it has a couple of array and object values.

Next, I’ll remove the parameters I don’t need.

I’ll keep the TableName (Pets) as well as the partition key and sort key parameters (AttributeDefinitions and KeySchema). I’ll also provision 2-2 read and write capacity units (BillingMode and ProvisionedThroughput) and will enable server-side encryption (SSESpecification) with the default AWS managed KMS customer master key (CMK), because I want the data about my pets to be secure.

After I have entered the values for the parameters I want and removed the ones I don’t want, my create-table.json looks like this:

{
  "AttributeDefinitions": [
    {
      "AttributeName": "Id",
      "AttributeType": "S"
    },
    {
      "AttributeName": "Name",
      "AttributeType": "S"
    }
  ],
  "TableName": "Pets",
  "KeySchema": [
    {
      "AttributeName": "Id",
      "KeyType": "HASH"
    },
    {
      "AttributeName": "Name",
      "KeyType": "RANGE"
    }
  ],
  "BillingMode": "PROVISIONED",
  "ProvisionedThroughput": {
    "ReadCapacityUnits": 2,
    "WriteCapacityUnits": 2
  },
  "SSESpecification": {
    "Enabled": true,
    "SSEType": "KMS"
  }
}

I have chosen the Id to be the partition key (it’s a good choice because it will be a UUID) and the Name of the pet will be the sort key.

I can now run the command and create the table:

aws dynamodb create-table --cli-input-json file://create-table.json

As a result, the Pets table will be created:

aws dynamodb list-tables

The response is

{
  "TableNames": [
    "Pets"
  ]
}

Great!

2.2. Add an item to the table

The table has been created and I can now add a pet to the table.

I’ll do the same as I did above with the PutItem API command:

aws dynamodb put-item --generate-cli-skeleton > put-item.json

I want to add a goldfish called Goldie who is one year old and doesn’t remember anything that happens around him in the world.

I also want to make sure that Goldie doesn’t exist in the table and I won’t override him accidentally, so I will conditionally write him to the table (attribute_not_exists). I also want to see how many write capacity units will Goldie consume.

After removing the unnecessary parameters and adding my values to it, the put-item.json file looks like this:

{
  "TableName": "Pets",
  "Item": {
    "Id": {
      "S": "6663f471-7247-4868-8faf-b42ecc35c7dd"
    },
    "Name": {
      "S": "Goldie"
    },
    "Type": {
      "S": "fish"
    },
    "Age": {
      "N": "1"
    },
    "Remembers": {
      "BOOL": false
    }
  },
  "ReturnConsumedCapacity": "TOTAL",
  "ConditionExpression": "attribute_not_exists(Id)"
}

Let’s run the command:

aws dynamodb put-item --cli-input-json file://put-item.json

The response will show the write capacity units used:

{
  "ConsumedCapacity": {
    "TableName": "Pets",
    "CapacityUnits": 1.0
  }
}

It’s only 1.0 WCU, so the provisioned 2 write capacity units have been proved to be enough.

If I quickly run a scan command (without generate-cli-skeleton):

aws dynamodb scan --table-name Pets

I can see that Goldie has been successfully written to the table:

{
  "Items": [
    {
      "Id": {
        "S": "6663f471-7247-4868-8faf-b42ecc35c7dd"
      },
      "Type": {
        "S": "fish"
      },
      "Age": {
        "N": "1"
      },
      "Remembers": {
        "BOOL": false
      },
      "Name": {
        "S": "Goldie"
      }
    }
  ],
  "Count": 1,
  "ScannedCount": 1,
  "ConsumedCapacity": null
}

And he really doesn’t remember anything.

3. Summary

Some CLI commands require parameter values of complex structure or have lots of compulsory parameters.

The generate-cli-skeleton parameter returns all available parameters with some default values. These parameters can be redirected to a JSON file, which can be modified in an editor. By referring to this file instead of typing the parameter values to the terminal will make running commands faster and less error prone.

Thanks for reading and see you next time.