Uses rkshell
to run the aws
command line tool from Racket.
Example usage (using raco run
:
$ raco run control.rkt start
$ raco run control.rkt stop
#lang rkshell/base | |
(require racket/match | |
racket/string | |
racket/system | |
syntax/parse/define | |
json | |
rkshell/private/repl) | |
(define instance-id "i-abc123") | |
(define zone-id "/hostedzone/zonezonezon") | |
(define dns-name "something.example.com.") | |
(define (raise-error-runner cmd . args) | |
(define errp (open-output-string)) | |
(define outp (open-output-string)) | |
(define result | |
(parameterize ([current-error-port errp] | |
[current-output-port outp] | |
[current-input-port (open-input-bytes #"")]) | |
(apply system* (rkshell-find-in-path cmd) args))) | |
(if result | |
(string->jsexpr (get-output-string outp)) | |
(error (string->symbol cmd) | |
(string-trim (get-output-string errp))))) | |
(rkexec-runner raise-error-runner) | |
(define (make-route53-change ip-address) | |
(hash | |
'Changes | |
(list | |
(hash 'Action "UPSERT" | |
'ResourceRecordSet | |
(hash 'Name dns-name | |
'Type "A" | |
'TTL 60 | |
'ResourceRecords | |
(list (hash 'Value ip-address))))))) | |
(define-simple-macro (run-async e) | |
(handle-evt (thread (lambda () e)) void)) | |
(define (notify-every secs msg) | |
(define (repeat cancel-evt) | |
(sync (handle-evt (alarm-evt (+ (current-inexact-milliseconds) (* 1000 secs))) | |
(lambda (e) (displayln msg) (repeat cancel-evt))) | |
(handle-evt cancel-evt void))) | |
(nack-guard-evt | |
(lambda (cancel-evt) | |
(thread (lambda () (repeat cancel-evt)))))) | |
(module* start #f | |
(displayln "starting instance") | |
#{aws ec2 start-instances | |
--output json | |
--instance-ids $instance-id} | |
(sync | |
(notify-every 2 "waiting for instance to start") | |
(run-async #{aws ec2 wait instance-running --instance-ids $instance-id})) | |
(define public-ip-address | |
#{aws ec2 describe-instances | |
--query "Reservations[0].Instances[0].PublicIpAddress" | |
--output json | |
--instance-ids $instance-id}) | |
(displayln "setting IP address") | |
(match-define | |
(hash-table ['ChangeInfo (hash-table ['Id change-id])]) | |
#{aws route53 change-resource-record-sets | |
--hosted-zone-id $zone-id | |
--change-batch (jsexpr->string (make-route53-change public-ip-address))}) | |
(sync | |
(notify-every 2 "waiting for dns to change") | |
(run-async #{aws route53 wait resource-record-sets-changed --id $change-id}))) | |
(module* stop #f | |
#{aws ec2 stop-instances --instance-ids $instance-id} | |
(sync | |
(notify-every 2 "waiting for instance to stop") | |
(run-async #{aws ec2 wait instance-stopped --instance-ids $instance-id}))) |