Welcome back! It’s been a week or two since my last post on this subject, but here it is! Today, I’m going to talk about how to interact with AWS EC2 using the amazonka and amazonka-ec2 packages. EC2, like Lambda, is a more involved service than some of the others. Furthermore, because the APIs I’ll talk about in this post are used to start and stop real, live, actual virtual machines, some of the APIs take longer to run and consume more AWS resources. Fortunately, the AWS free tier provides sufficient juice to learn how to use the APIs.
There are many moving parts to EC2. Consequently, the EC2 API is big. If you don’t believe me, then feel free to check out the number of types in amazonka-ec2. I have managed to pare down the APIs required to produce a minimally useful demo that demonstrates the following:
The end result is a program that will start an EC2 instance and provide enough information for users to connect to the instance via SSH. The resulting example program will run a single instance of one of the standard Amazon Linux AMIs. It will assume that you have a private-public key pair in the standard locations, i.e. $HOME/.ssh/id_rsa
and $HOME/.ssh/id_rsa.pub
, on your system. To grab the key pairs from a different location, please edit the program as necessary. Windows users will need to generate an ssh-keygen
-style key pair using PuTTY or similar and edit the program as appropriate. The program will import the public portion of your key pair in order to allow remote access to your newly created EC2 instance.
Since my previous instalments, the shared code has undergone some more refactoring. I’ve simplified some of the names and also introduced an AWS-specific prelude in the form of AWSViaHaskell.Prelude
:
This imports the most commonly used amazonka functions and types in order to slim down the import lists in each Haskell sample. This is the best approach I have devised so far to deal with “Haskell import hell”. Similarly, I have extracted all the amazonka-ec2 imports for this program in the form of EC2Imports.hs
:
To run this example code, you’ll need access to EC2. The most obvious way is to use the AWS free tier. This code will assume that you set up an appropriate account. Unfortunately, I have not yet found a local-only test environment for this kind of thing. localstack does not, yet, provide emulation of EC2.
We have a pretty standard set of dependencies:
amazonka-ec2
aws-via-haskell
base
bytestring
directory
filepath
lens
text
You’ll notice that we do not require a direct dependency on amazonka
. This is handled by the re-exports provided by AWSViaHaskell.Prelude
.
We generate type-safe wrappers for the EC2 service using wrapAWSService
:
This generates the following items:
ec2Service
EC2Service
EC2Session
newtype
wrappers for function argumentsWe declare a number of newtype
wrappers around the Text
type. These are intended to prevent the developer from passing one type of Text
when a function expects another Text
.
Aside: amazonka, like many frameworks, is somewhat “stringly-typed” and this is my attempt to impose some order on some of its functions which take multiple Text
arguments. In fact, there is concrete example of a bug resulting from stringly-typeness and code generation where the order of multiple Text
arguments have been changed between version 1.4.5 and 1.5.0. This results in unfortunately runtime bugs in the code. newtype
wrappers for my sample functions here should minimize the chance of this happening at least at the level of these new functions.
main
function$HOME/.ssh/id_rsa.pub
_DuplicateKeyPair
: many of the other amazonka subpackages provide custom error matchers which is not the case for amazonka-ec2, presumably because the number of errors that are routinely encountered in EC2 land is large: fortunately, it’s straightforward to implement custom matchers for the kinds of errors we’ll encounter in our simple example_DuplicateGroup
Here is the code:
So, this should be enough to provision all the resources required to run an instance and to provide an ssh
command line to connect to it.
Don’t forget to terminate the EC2 instance after you’re done!
I’ve gathered this all together into this buildable project. As always, I like to build using Stack.
Content © 2024 Richard Cook. All rights reserved.