Last active
October 25, 2024 08:14
-
-
Save dontlaugh/1ccf92015d2e990b95b6ebeaa32cdc13 to your computer and use it in GitHub Desktop.
Deno AWS cli example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env -S deno run --allow-read --allow-net --allow-run | |
/* | |
This script prints out a list of VPCs, subnets, and route tables. | |
The output will be different depending on which AWS account you are | |
connected to. | |
*/ | |
const {stdout, copy} = Deno; | |
import iro, { | |
bold, red, dim, yellow, white, blue, cyan, green | |
} from "https://cdn.jsdelivr.net/npm/[email protected]/src/iro.ts"; | |
async function main() { | |
let networks = new Array<Network>(); | |
let vpcs: Vpc[] = await getVpcs(); | |
for (let vpc of vpcs) { | |
let n = await buildNetwork(vpc); | |
networks.push(n); | |
} | |
for (let [vpc, subnets, routeTables] of networks) { | |
let vpcName = iro(vpc.name, bold, yellow); | |
let vpcId = iro(vpc.id, dim, yellow); | |
let vpcLabel = iro("vpc:", dim, white); | |
let vpcCidr = iro(vpc.cidrBlock, dim, yellow) | |
console.log(`${vpcLabel} ${vpcName} ${vpcId} ${vpcCidr}`); | |
let numSubnets = iro(`number of subnets: ${subnets.length}`, dim, cyan); | |
console.log(numSubnets); | |
for (let sn of subnets) { | |
let subnetName = iro(sn.name, bold, blue); | |
let subnetId = iro(sn.id, dim, blue); | |
console.log(` ${subnetId} ${subnetName}`) | |
} | |
for (let rt of routeTables) { | |
let rtId = iro(`${rt.id}`, green) | |
let mainRt = iro(rt.main ? "main" : "", bold, red) | |
let routeTableLabel = iro("route table", green, dim); | |
let routes = iro(rt.routes.join(" "), bold, green) | |
let routesLabel = iro("routes: ", dim, green) | |
let assocLabel = iro("associations: ", dim, green) | |
let assoc = iro(rt.assocations.join(" "), dim, green) | |
console.log(` ${routeTableLabel} ${rtId} ${mainRt}`) | |
console.log(` ${routesLabel} ${routes}`) | |
console.log(` ${assocLabel} ${assoc}`) | |
} | |
console.log(""); | |
} | |
} | |
async function buildNetwork(vpc: Vpc): Promise<Network> { | |
let subnets = await getSubnets(vpc.id); | |
let routeTables = await getRouteTables(vpc.id); | |
return [vpc, subnets, routeTables]; | |
} | |
async function getVpcs(withDefaultVpc: boolean = false): Promise<Vpc[]> { | |
let [success, output] = await commandWithOutput( | |
["aws", "ec2", "describe-vpcs", "--filter", `Name=isDefault,Values=${withDefaultVpc}`]); | |
if (!success) throw Error("getVpcs failed") | |
const decoder = new TextDecoder('utf-8'); | |
let response: Array<{[key: string]: any}> = JSON.parse(decoder.decode(output))["Vpcs"]; | |
let vpcs = new Array<Vpc>(); | |
for (let obj of response) { | |
let vpc: Vpc = { | |
cidrBlock: obj["CidrBlock"], | |
name: getAWSTag("Name", obj["Tags"]), | |
id: obj["VpcId"], | |
}; | |
vpcs.push(vpc); | |
} | |
return vpcs; | |
} | |
async function getRouteTables(vpcId: string): Promise<RouteTable[]> { | |
let [success, output] = await commandWithOutput( | |
["aws", "ec2", "describe-route-tables", "--filters", `Name=vpc-id,Values=${vpcId}`]); | |
if (!success) { | |
throw Error("getRouteTables failed") | |
} | |
const decoder = new TextDecoder('utf-8'); | |
let rts: Array<{[key: string]: any}> = JSON.parse(decoder.decode(output))["RouteTables"]; | |
let routeTables = new Array<RouteTable>(); | |
for (let obj of rts) { | |
let isMain: boolean = obj["Associations"].filter((assoc: {[key: string]: any}) => { | |
if (assoc.hasOwnProperty("Main")) { | |
return assoc["Main"]; | |
} | |
}).length == 1; | |
let associations: string[] = obj["Associations"] | |
.filter((assoc: {[key: string]: any}) => assoc.hasOwnProperty("SubnetId")) | |
.map((assoc: {[key: string]: any}) => { | |
return assoc["SubnetId"] | |
}); | |
let routes: string[] = obj["Routes"].map((r: {[key: string]: any})=> { | |
return r["DestinationCidrBlock"] | |
}); | |
let rt: RouteTable = { | |
id: obj["RouteTableId"], | |
main: isMain, | |
assocations: associations, | |
routes: routes, | |
}; | |
routeTables.push(rt); | |
} | |
return routeTables; | |
} | |
async function getSubnets(vpcId: string): Promise<Subnet[]> { | |
let [success, output] = await commandWithOutput( | |
["aws", "ec2", "describe-subnets", "--filters", `Name=vpc-id,Values=${vpcId}`]); | |
if (!success) { | |
throw Error("getSubnets failed") | |
} | |
const decoder = new TextDecoder('utf-8'); | |
let response: Array<{[key: string]: any}> = JSON.parse(decoder.decode(output))["Subnets"]; | |
let subnets = new Array<Subnet>(); | |
for (let obj of response) { | |
let s: Subnet = { | |
id: obj["SubnetId"], | |
name: getAWSTag("Name", obj["Tags"]), | |
}; | |
subnets.push(s); | |
} | |
return subnets; | |
} | |
async function commandWithOutput(cmd: string[]): Promise<[boolean, ArrayBuffer]> { | |
let result = Deno.run({ | |
cmd: cmd, | |
stdout: "piped", | |
}); | |
let status = await result.status(); | |
let output = await result.output(); | |
return [status.success, output]; | |
} | |
function getAWSTag(key: string, tags: Array<{[key: string]: string}>): string { | |
let filtered = tags.filter((o) => o["Key"] == key); | |
if (filtered.length < 1) { | |
return `(${key} MISSING)` | |
} | |
return filtered[0]["Value"]; | |
} | |
interface Vpc { | |
id: string, | |
name: string, | |
cidrBlock: string, | |
} | |
interface Subnet { | |
id: string, | |
name: string, | |
} | |
interface RouteTable { | |
id: string | |
main: boolean, | |
routes: string[], | |
assocations: string[], | |
} | |
type Network = [Vpc, Subnet[], RouteTable[]]; | |
await main(); | |
/* | |
TODO: More aws ec2 subecommands: | |
describe-local-gateway-route-tables | |
describe-local-gateways | |
describe-nat-gateways | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment