diff --git a/aws/vpc/MANIFEST b/aws/vpc/MANIFEST new file mode 100644 index 0000000..b60905a --- /dev/null +++ b/aws/vpc/MANIFEST @@ -0,0 +1,3 @@ +REPO vpc +LOAD vpc.yaml example.yaml +RESOURCES vpc.js diff --git a/aws/vpc/README.md b/aws/vpc/README.md new file mode 100644 index 0000000..f2ccb9b --- /dev/null +++ b/aws/vpc/README.md @@ -0,0 +1,25 @@ +# VPC + +Entity to manage VPC Resource. +It will allow us to create new VPC Resource. + +## Usage + +We'll use Monk CLI to load and create our database instance. +Copy `example.yaml` and update the vars according to your needs. +Full schema available here: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateVpc.html + + # load templates + monk load vpc.yml .yml + + # run to trigger a "create" event + monk run / + +VPC Resource should be created for you in the specified region. + + +To delete it `monk delete`: + + monk delete / + +This should remove Entity from Monk and the VPC resource from AWS. diff --git a/aws/vpc/example.yaml b/aws/vpc/example.yaml new file mode 100644 index 0000000..4f65b4e --- /dev/null +++ b/aws/vpc/example.yaml @@ -0,0 +1,9 @@ +namespace: aws + +my-vpc: + defines: aws/vpc + region: eu-north-1 + name: monk + cidr: 10.0.0.0/16 + dns-resolution: true + dns-hostnames: true \ No newline at end of file diff --git a/aws/vpc/vpc.js b/aws/vpc/vpc.js new file mode 100644 index 0000000..ef5a044 --- /dev/null +++ b/aws/vpc/vpc.js @@ -0,0 +1,217 @@ +let aws = require("cloud/aws"); +let cli = require("cli"); +let http = require("http"); +let secret = require("secret"); +const parser = require("parser"); +const { stat } = require("fs"); + +function getDateString() { + let date = new Date(); + let month = date.getMonth() + 1; + let day = date.getDate(); + let year = date.getFullYear(); + let hour = date.getHours(); + let minute = date.getMinutes(); + let second = date.getSeconds(); + return year + "" + month + "" + day + "-" + hour + "" + minute + "" + second; +} +function encodeQueryData(data) { + const ret = []; + for (let d in data) + ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d])); + return ret.join('&'); +} + + +let createVPC = function (def) { + cli.output("createVPC"); + data = { + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "service": "ec2", + "region": def["region"] + }; + let param = { + "CidrBlock": def["cidr"], + "Version": "2016-11-15" + } + + const searchParams = encodeQueryData(param); + cli.output("https://ec2." + def["region"] + ".amazonaws.com/?Action=CreateVpc&" + searchParams.toString()); + // Create aws rds instance + let res = aws.post("https://ec2." + def["region"] + ".amazonaws.com/?Action=CreateVpc&" + searchParams.toString(), { + "headers": data.headers, + "service": data.service, + "region": data.region + }); + + if (res.error) { + errorMessage = parser.xmlquery(res.body, "//ErrorResponse/Error/Message"); + throw new Error(res.error + ", " + errorMessage); + } + + let state = { + "vpcStatus": parser.xmlquery(res.body, "//CreateVpcResponse/vpc/state")[0], + "vpcId": parser.xmlquery(res.body, "//CreateVpcResponse/vpc/vpcId")[0], + } + return state +} + + + +let deleteVPC = function (def, state) { + cli.output("deleteVPC"); + + cli.output(JSON.stringify(state)); + data = { + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "service": "ec2", + "region": def["region"] + }; + + let param = { + "VpcId": state["vpcId"], + "Version": "2016-11-15" + } + + const searchParams = encodeQueryData(param); + cli.output("https://ec2." + def["region"] + ".amazonaws.com/?Action=DeleteVpc&" + searchParams.toString()); + // Create aws rds instance + let res = aws.post("https://ec2." + def["region"] + ".amazonaws.com/?Action=DeleteVpc&" + searchParams.toString(), { + "headers": data.headers, + "service": data.service, + "region": data.region + }); + + if (res.error) { + errorMessage = parser.xmlquery(res.body, "//ErrorResponse/Error/Message"); + throw new Error(res.error + ", " + errorMessage); + } + + return { + "status": "deleted" + } + +} + +let getVPC = function (def, state) { + cli.output("getVPC"); + data = { + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "service": "ec2", + "region": def["region"] + }; + + let param = { + "VpcId.1": state["vpcId"], + "Version": "2016-11-15" + } + + const searchParams = encodeQueryData(param); + cli.output("https://ec2." + def["region"] + ".amazonaws.com/?Action=DescribeVpcs&" + searchParams.toString()); + // Create aws rds instance + let res = aws.post("https://ec2." + def["region"] + ".amazonaws.com/?Action=DescribeVpcs&" + searchParams.toString(), { + "headers": data.headers, + "service": data.service, + "region": data.region + }); + + if (res.error) { + errorMessage = parser.xmlquery(res.body, "//ErrorResponse/Error/Message"); + throw new Error(res.error + ", " + errorMessage); + } + let lastState = { + "vpcStatus": parser.xmlquery(res.body, "//DescribeVpcsResponse/vpcSet/item/state")[0], + "vpcId": parser.xmlquery(res.body, "//DescribeVpcsResponse/vpcSet/item/vpcId")[0], + } + return lastState; + +} + +let modifyVPCRequest = function (def, state, key, value) { + cli.output("getVPC"); + data = { + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "service": "ec2", + "region": def["region"] + }; + + let param = { + "VpcId": state["vpcId"], + "Version": "2016-11-15", + [key]: value + } + + const searchParams = encodeQueryData(param); + cli.output("https://ec2." + def["region"] + ".amazonaws.com/?Action=ModifyVpcAttribute&" + searchParams.toString()); + // Create aws rds instance + let res = aws.post("https://ec2." + def["region"] + ".amazonaws.com/?Action=ModifyVpcAttribute&" + searchParams.toString(), { + "headers": data.headers, + "service": data.service, + "region": data.region + }); + + if (res.error) { + return false; + } + return true; + +} + +let modifyVPC = function (def, state) { + if (def['dns-resolution']) { + state["dnsResolution"] = modifyVPCRequest(def, state, "EnableDnsSupport.Value", def['dns-resolution']); + } + + if (def['dns-hostnames']) { + state["dnsHostnames"] = modifyVPCRequest(def, state, "EnableDnsHostnames.Value", def['dns-hostnames']); + } + return state; +} + +let checkReadiness = function (def, state) { + cli.output("checkReadiness"); + state = getVPC(def, state); + if (state.vpcStatus !== "available") { + throw new Error("VPC is not ready yet. Current status: " + state.vpcStatus); + } + return modifyVPC(def, state); +} + + +function main(def, state, ctx) { + cli.output(ctx.action); + let res = {}; + switch (ctx.action) { + case "recreate": + case "create": + state = createVPC(def) + break; + case "purge": + state = deleteVPC(def, state); + break; + case "get": + state = getVPC(def, state); + break; + case "modify": { + state = modifyVPC(def, state) + break; + } + case "check-readiness": { + state = checkReadiness(def, state) + break; + } + default: + // no action defined + return; + } + + return state; +} diff --git a/aws/vpc/vpc.yaml b/aws/vpc/vpc.yaml new file mode 100644 index 0000000..09eec92 --- /dev/null +++ b/aws/vpc/vpc.yaml @@ -0,0 +1,30 @@ +namespace: aws + +vpc: + defines: entity + schema: + required: [ name, cidr ] + name: + type: string + cidr: + type: string + dns-resolution: + type: boolean + default: true + dns-hostnames: + type: boolean + default: true + + requires: + - cloud/aws + lifecycle: + sync: <<< vpc.js + update: "" + recreate: "" + get: "" + modify: "" + checks: + readiness: + code: "" + period: 40 + attempts: 15