diff --git a/src/TerraformGenerator.ts b/src/TerraformGenerator.ts index 723e8e5..a9fcc4f 100644 --- a/src/TerraformGenerator.ts +++ b/src/TerraformGenerator.ts @@ -2,7 +2,7 @@ import child_process from 'child_process'; import fs from 'fs'; import path from 'path'; import shell from 'shelljs'; -import { Block, Comment, Resource, Data, Module, Output, Provider, Variable, Backend, Provisioner, ResourceToDataOptions, Locals, Import, ImportArgs, VariableArgs, ModuleArgs, OutputArgs } from './blocks'; +import { Block, Comment, Resource, Data, Module, Output, Provider, Variable, Backend, Provisioner, ResourceToDataOptions, Locals, Import, ImportArgs, VariableArgs, ModuleArgs, OutputArgs, Moved, MovedArgs, RemovedArgs, Removed } from './blocks'; import { TerraformArgs, Util } from './utils'; /** @@ -313,6 +313,32 @@ export class TerraformGenerator { return block; } + /** + * Add moved into Terraform. + * + * Refer to Terraform documentation on what can be put as type & arguments. + * + * @param args arguments + */ + moved(args: MovedArgs): Moved { + const block = new Moved(args); + this.addBlocks(block); + return block; + } + + /** + * Add removed into Terraform. + * + * Refer to Terraform documentation on what can be put as type & arguments. + * + * @param args arguments + */ + removed(args: RemovedArgs): Removed { + const block = new Removed(args); + this.addBlocks(block); + return block; + } + /** * Add variable values into Terraform. * diff --git a/src/blocks/Moved.ts b/src/blocks/Moved.ts new file mode 100644 index 0000000..81ad020 --- /dev/null +++ b/src/blocks/Moved.ts @@ -0,0 +1,37 @@ +import { Argument, Attribute } from '../arguments'; +import { Util } from '../utils'; +import { Block, Resource } from '.'; + +/** + * @category Block + */ +export interface MovedArgs { + from: Argument; + to: Argument | Resource; +} + +/** + * @category Block + */ +export class Moved extends Block { + + /** + * Construct moved. + * + * Refer to Terraform documentation on what can be put as arguments. + * + * @param args arguments + */ + constructor(args: MovedArgs) { + super('moved', [], args); + } + + override asArgument(): Argument { + throw Util.inaccessibleMethod(); + } + + override attr(_name: string): Attribute { + throw Util.inaccessibleMethod(); + } + +} diff --git a/src/blocks/Removed.ts b/src/blocks/Removed.ts new file mode 100644 index 0000000..d933b5a --- /dev/null +++ b/src/blocks/Removed.ts @@ -0,0 +1,39 @@ +import { Argument, Attribute } from '../arguments'; +import { Util } from '../utils'; +import { Block } from '.'; + +/** + * @category Block + */ +export interface RemovedArgs { + from: Argument; + lifecycle: { + destroy: boolean; + }; +} + +/** + * @category Block + */ +export class Removed extends Block { + + /** + * Construct removed. + * + * Refer to Terraform documentation on what can be put as arguments. + * + * @param args arguments + */ + constructor(args: RemovedArgs) { + super('removed', [], args); + } + + override asArgument(): Argument { + throw Util.inaccessibleMethod(); + } + + override attr(_name: string): Attribute { + throw Util.inaccessibleMethod(); + } + +} diff --git a/src/blocks/index.ts b/src/blocks/index.ts index 1b675df..013e27f 100644 --- a/src/blocks/index.ts +++ b/src/blocks/index.ts @@ -5,8 +5,10 @@ export * from './Data'; export * from './Import'; export * from './Locals'; export * from './Module'; +export * from './Moved'; export * from './Output'; export * from './Provider'; export * from './Provisioner'; +export * from './Removed'; export * from './Resource'; export * from './Variable'; diff --git a/test/blocks/Moved.test.ts b/test/blocks/Moved.test.ts new file mode 100644 index 0000000..636989e --- /dev/null +++ b/test/blocks/Moved.test.ts @@ -0,0 +1,23 @@ +import { arg } from '../../src/arguments'; +import { Moved, Resource } from '../../src/blocks'; + +test('To argument', () => { + const moved = new Moved({ + from: arg('resource.a'), + to: arg('resource.b') + }); + expect(moved.toTerraform()).toMatchSnapshot(); + expect(() => moved.asArgument()).toThrow(); + expect(() => moved.attr('attr')).toThrow(); +}); + +test('To resource', () => { + const resource = new Resource('resource', 'b'); + const moved = new Moved({ + from: arg('resource.a'), + to: resource + }); + expect(moved.toTerraform()).toMatchSnapshot(); + expect(() => moved.asArgument()).toThrow(); + expect(() => moved.attr('attr')).toThrow(); +}); diff --git a/test/blocks/Removed.test.ts b/test/blocks/Removed.test.ts new file mode 100644 index 0000000..6df3aea --- /dev/null +++ b/test/blocks/Removed.test.ts @@ -0,0 +1,14 @@ +import { arg } from '../../src/arguments'; +import { Removed } from '../../src/blocks'; + +test('Removed', () => { + const moved = new Removed({ + from: arg('resource.a'), + lifecycle: { + destroy: false + } + }); + expect(moved.toTerraform()).toMatchSnapshot(); + expect(() => moved.asArgument()).toThrow(); + expect(() => moved.attr('attr')).toThrow(); +}); diff --git a/test/blocks/__snapshots__/Moved.test.ts.snap b/test/blocks/__snapshots__/Moved.test.ts.snap new file mode 100644 index 0000000..b826f07 --- /dev/null +++ b/test/blocks/__snapshots__/Moved.test.ts.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`To argument 1`] = ` +"moved{ +from = resource.a +to = resource.b +} + +" +`; + +exports[`To resource 1`] = ` +"moved{ +from = resource.a +to = resource.b +} + +" +`; diff --git a/test/blocks/__snapshots__/Removed.test.ts.snap b/test/blocks/__snapshots__/Removed.test.ts.snap new file mode 100644 index 0000000..67c45df --- /dev/null +++ b/test/blocks/__snapshots__/Removed.test.ts.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Removed 1`] = ` +"removed{ +from = resource.a +lifecycle { +destroy = false +} +} + +" +`; diff --git a/test/tfg/Others.test.ts b/test/tfg/Others.test.ts index e47b227..a3babf5 100644 --- a/test/tfg/Others.test.ts +++ b/test/tfg/Others.test.ts @@ -1,6 +1,6 @@ import fs from 'fs'; import path from 'path'; -import { arg, map } from '../../src/arguments'; +import { Argument, arg, map } from '../../src/arguments'; import { Provisioner } from '../../src/blocks'; import { TerraformGenerator } from '../../src/TerraformGenerator'; @@ -75,6 +75,18 @@ const createTerraformGenerator = (): TerraformGenerator => { line4 `); + tfg.moved({ + from: new Argument('resource.a'), + to: resource + }); + + tfg.removed({ + from: new Argument('resource.b'), + lifecycle: { + destroy: false + } + }); + const tfg2 = new TerraformGenerator(); tfg2.resource('tfg2', 'tfg2', { tfg2: 'tfg2' diff --git a/test/tfg/__snapshots__/Others.test.ts.snap b/test/tfg/__snapshots__/Others.test.ts.snap index 4cfc382..8680f3c 100644 --- a/test/tfg/__snapshots__/Others.test.ts.snap +++ b/test/tfg/__snapshots__/Others.test.ts.snap @@ -111,6 +111,14 @@ exports[`Others 2`] = ` line4 ", }, + Moved { + "blockNames": [], + "blockType": "moved", + }, + Removed { + "blockNames": [], + "blockType": "removed", + }, Resource { "blockNames": [ "tfg2", @@ -214,6 +222,18 @@ b = "b c d" # line3 # line4 +moved{ +from = resource.a +to = innerBlock.innerBlock +} + +removed{ +from = resource.b +lifecycle { +destroy = false +} +} + resource "tfg2" "tfg2"{ tfg2 = "tfg2" } @@ -226,91 +246,607 @@ tfg2 = "tfg2" `; exports[`Others 5`] = ` -"variable "test"{ -type = string +"terraform { +required_version = "= 0.12" +backend "s3"{ +bucket = "mybucket" +key = "path/to/my/key" +region = "ap-southeast-1" } -variable "test2"{ -type = string } -data "aws_vpc" "test"{ -cidr_block = "test" +provider "aws"{ +region = "ap-southeast-1" +profile = "test" } -module "test"{ -source = "./test" +resource "aws_vpc" "vpc"{ +cidr_block = "172.88.0.0/16" +tags = { +name = "vpc-test-dev" +project = "test" +env = "dev" +} } -resource "aws_vpc" "test"{ -cidr_block = "test" +resource "aws_subnet" "public0"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.100.0/24" +availability_zone = "ap-southeast-1a" tags = { -a = "a" +name = "subnet-test-dev-public0" +project = "test" +env = "dev" } } -data "aws_vpc" "test"{ -filter { -name = "tag:a" -values = [ -"a" -] +resource "aws_subnet" "public1"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.101.0/24" +availability_zone = "ap-southeast-1b" +tags = { +name = "subnet-test-dev-public1" +project = "test" +env = "dev" } -cidr_block = "test" } -data "aws_vpc" "test2"{ -filter { -name = "tag:a" -values = [ -"a" -] +resource "aws_subnet" "public2"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.102.0/24" +availability_zone = "ap-southeast-1c" +tags = { +name = "subnet-test-dev-public2" +project = "test" +env = "dev" } -cidr_block = "test" } -resource "innerBlock" "innerBlock"{ -a = "a" -provisioner "local-exec"{ -command = "echo hello" +resource "aws_subnet" "web0"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.104.0/24" +availability_zone = "ap-southeast-1a" +tags = { +name = "subnet-test-dev-web0" +project = "test" +env = "dev" } -provisioner "local-exec"{ -command = "echo world" +} + +resource "aws_subnet" "web1"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.105.0/24" +availability_zone = "ap-southeast-1b" +tags = { +name = "subnet-test-dev-web1" +project = "test" +env = "dev" } } -locals{ -a = "a" -b = 123 -c = aws_vpc.test.x +resource "aws_subnet" "web2"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.106.0/24" +availability_zone = "ap-southeast-1c" +tags = { +name = "subnet-test-dev-web2" +project = "test" +env = "dev" +} } -resource "locals" "locals"{ -a = local.a +resource "aws_subnet" "app0"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.108.0/24" +availability_zone = "ap-southeast-1a" +tags = { +name = "subnet-test-dev-app0" +project = "test" +env = "dev" +} } -import{ -to = innerBlock.innerBlock -id = "id" -provider = arg +resource "aws_subnet" "app1"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.109.0/24" +availability_zone = "ap-southeast-1b" +tags = { +name = "subnet-test-dev-app1" +project = "test" +env = "dev" +} } -resource "tags" "tags"{ +resource "aws_subnet" "app2"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.110.0/24" +availability_zone = "ap-southeast-1c" tags = { -a = "a" -b = "b c d" +name = "subnet-test-dev-app2" +project = "test" +env = "dev" } } -# comment +resource "aws_subnet" "gut0"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.112.0/24" +availability_zone = "ap-southeast-1a" +tags = { +name = "subnet-test-dev-gut0" +project = "test" +env = "dev" +} +} -# line1 -# line2 -# line3 -# line4 +resource "aws_subnet" "gut1"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.113.0/24" +availability_zone = "ap-southeast-1b" +tags = { +name = "subnet-test-dev-gut1" +project = "test" +env = "dev" +} +} -resource "tfg2" "tfg2"{ -tfg2 = "tfg2" +resource "aws_subnet" "gut2"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.114.0/24" +availability_zone = "ap-southeast-1c" +tags = { +name = "subnet-test-dev-gut2" +project = "test" +env = "dev" +} +} + +resource "aws_subnet" "db0"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.116.0/24" +availability_zone = "ap-southeast-1a" +tags = { +name = "subnet-test-dev-db0" +project = "test" +env = "dev" +} +} + +resource "aws_subnet" "db1"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.117.0/24" +availability_zone = "ap-southeast-1b" +tags = { +name = "subnet-test-dev-db1" +project = "test" +env = "dev" +} +} + +resource "aws_subnet" "db2"{ +vpc_id = aws_vpc.vpc.id +cidr_block = "172.88.118.0/24" +availability_zone = "ap-southeast-1c" +tags = { +name = "subnet-test-dev-db2" +project = "test" +env = "dev" +} +} + +resource "aws_internet_gateway" "igw"{ +vpc_id = aws_vpc.vpc.id +tags = { +name = "igw-test-dev" +project = "test" +env = "dev" +} +} + +resource "aws_route_table" "default"{ +vpc_id = aws_vpc.vpc.id +tags = { +name = "rt-test-dev-default" +project = "test" +env = "dev" +} +} + +resource "aws_route_table" "igw"{ +vpc_id = aws_vpc.vpc.id +route { +cidr_block = "0.0.0.0/0" +gateway_id = aws_internet_gateway.igw.id +} +tags = { +name = "rt-test-dev-igw" +project = "test" +env = "dev" +} +} + +resource "aws_route_table_association" "default-web0"{ +subnet_id = aws_subnet.web0.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-web1"{ +subnet_id = aws_subnet.web1.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-web2"{ +subnet_id = aws_subnet.web2.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-app0"{ +subnet_id = aws_subnet.app0.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-app1"{ +subnet_id = aws_subnet.app1.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-app2"{ +subnet_id = aws_subnet.app2.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-gut0"{ +subnet_id = aws_subnet.gut0.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-gut1"{ +subnet_id = aws_subnet.gut1.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-gut2"{ +subnet_id = aws_subnet.gut2.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-db0"{ +subnet_id = aws_subnet.db0.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-db1"{ +subnet_id = aws_subnet.db1.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "default-db2"{ +subnet_id = aws_subnet.db2.id +route_table_id = aws_route_table.default.id +} + +resource "aws_route_table_association" "igw-public0"{ +subnet_id = aws_subnet.public0.id +route_table_id = aws_route_table.igw.id +} + +resource "aws_route_table_association" "igw-public1"{ +subnet_id = aws_subnet.public1.id +route_table_id = aws_route_table.igw.id +} + +resource "aws_route_table_association" "igw-public2"{ +subnet_id = aws_subnet.public2.id +route_table_id = aws_route_table.igw.id +} + +resource "aws_network_acl" "default"{ +vpc_id = aws_vpc.vpc.id +subnet_ids = [ +aws_subnet.public0.id, +aws_subnet.public1.id, +aws_subnet.public2.id, +aws_subnet.web0.id, +aws_subnet.web1.id, +aws_subnet.web2.id, +aws_subnet.app0.id, +aws_subnet.app1.id, +aws_subnet.app2.id, +aws_subnet.gut0.id, +aws_subnet.gut1.id, +aws_subnet.gut2.id +] +ingress { +protocol = "all" +rule_no = 100 +action = "allow" +cidr_block = "0.0.0.0/0" +from_port = 0 +to_port = 0 +} +egress { +protocol = "all" +rule_no = 100 +action = "allow" +cidr_block = "0.0.0.0/0" +from_port = 0 +to_port = 0 +} +tags = { +name = "nacl-test-dev-default" +project = "test" +env = "dev" +} +} + +resource "aws_network_acl" "db"{ +vpc_id = aws_vpc.vpc.id +subnet_ids = [ +aws_subnet.db0.id, +aws_subnet.db1.id, +aws_subnet.db2.id +] +ingress { +protocol = "all" +rule_no = 100 +action = "allow" +cidr_block = "172.88.108.0/22" +from_port = 0 +to_port = 0 +} +ingress { +protocol = "all" +rule_no = 110 +action = "allow" +cidr_block = "172.88.116.0/22" +from_port = 0 +to_port = 0 +} +egress { +protocol = "all" +rule_no = 100 +action = "allow" +cidr_block = "172.88.108.0/22" +from_port = 0 +to_port = 0 +} +egress { +protocol = "all" +rule_no = 110 +action = "allow" +cidr_block = "172.88.116.0/22" +from_port = 0 +to_port = 0 +} +tags = { +name = "nacl-test-dev-db" +project = "test" +env = "dev" +} +} + +resource "aws_security_group" "public-default"{ +name = "fw-public-default" +description = "Default for public tier" +vpc_id = aws_vpc.vpc.id +ingress { +protocol = "tcp" +from_port = 22 +to_port = 22 +cidr_blocks = [ +"172.88.100.0/22" +] +description = "SSH for tier" +} +egress { +protocol = "-1" +from_port = 0 +to_port = 0 +cidr_blocks = [ +"0.0.0.0/0" +] +} +tags = { +name = "sg-test-dev-public-default" +project = "test" +env = "dev" +} +} + +resource "aws_security_group" "web-default"{ +name = "fw-web-default" +description = "Default for web tier" +vpc_id = aws_vpc.vpc.id +ingress { +protocol = "tcp" +from_port = 22 +to_port = 22 +cidr_blocks = [ +"172.88.104.0/22" +] +description = "SSH for tier" +} +egress { +protocol = "-1" +from_port = 0 +to_port = 0 +cidr_blocks = [ +"0.0.0.0/0" +] +} +tags = { +name = "sg-test-dev-web-default" +project = "test" +env = "dev" +} +} + +resource "aws_security_group" "app-default"{ +name = "fw-app-default" +description = "Default for app tier" +vpc_id = aws_vpc.vpc.id +ingress { +protocol = "tcp" +from_port = 22 +to_port = 22 +cidr_blocks = [ +"172.88.108.0/22" +] +description = "SSH for tier" +} +egress { +protocol = "-1" +from_port = 0 +to_port = 0 +cidr_blocks = [ +"0.0.0.0/0" +] +} +tags = { +name = "sg-test-dev-app-default" +project = "test" +env = "dev" +} +} + +resource "aws_security_group" "gut-default"{ +name = "fw-gut-default" +description = "Default for gut tier" +vpc_id = aws_vpc.vpc.id +ingress { +protocol = "tcp" +from_port = 22 +to_port = 22 +cidr_blocks = [ +"172.88.112.0/22" +] +description = "SSH for tier" +} +egress { +protocol = "-1" +from_port = 0 +to_port = 0 +cidr_blocks = [ +"0.0.0.0/0" +] +} +tags = { +name = "sg-test-dev-gut-default" +project = "test" +env = "dev" +} +} + +resource "aws_security_group" "db-default"{ +name = "fw-db-default" +description = "Default for db tier" +vpc_id = aws_vpc.vpc.id +ingress { +protocol = "tcp" +from_port = 22 +to_port = 22 +cidr_blocks = [ +"172.88.116.0/22" +] +description = "SSH for tier" +} +egress { +protocol = "-1" +from_port = 0 +to_port = 0 +cidr_blocks = [ +"0.0.0.0/0" +] +} +tags = { +name = "sg-test-dev-db-default" +project = "test" +env = "dev" +} +} + +resource "aws_eip" "nat"{ +vpc = true +tags = { +name = "eip-test-dev-nat" +project = "test" +env = "dev" +} +} + +resource "aws_nat_gateway" "nat"{ +allocation_id = aws_eip.nat.id +subnet_id = aws_subnet.public0.id +tags = { +name = "nat-test-dev" +project = "test" +env = "dev" +} +} + +resource "aws_route_table" "nat"{ +vpc_id = aws_vpc.vpc.id +route { +cidr_block = "0.0.0.0/0" +gateway_id = aws_nat_gateway.nat.id +} +tags = { +name = "rt-test-dev-nat" +project = "test" +env = "dev" +} +} + +resource "aws_route_table_association" "nat-gut0"{ +subnet_id = aws_subnet.gut0.id +route_table_id = aws_route_table.nat.id +} + +resource "aws_route_table_association" "nat-gut1"{ +subnet_id = aws_subnet.gut1.id +route_table_id = aws_route_table.nat.id +} + +resource "aws_route_table_association" "nat-gut2"{ +subnet_id = aws_subnet.gut2.id +route_table_id = aws_route_table.nat.id +} + +output "vpc"{ +value = { +cidr = aws_vpc.vpc.cidr_block +} +} + +output "subnets"{ +value = { +publicSubnets = [ +aws_subnet.public0.cidr_block, +aws_subnet.public1.cidr_block, +aws_subnet.public2.cidr_block +] +webSubnets = [ +aws_subnet.web0.cidr_block, +aws_subnet.web1.cidr_block, +aws_subnet.web2.cidr_block +] +appSubnets = [ +aws_subnet.app0.cidr_block, +aws_subnet.app1.cidr_block, +aws_subnet.app2.cidr_block +] +gutSubnets = [ +aws_subnet.gut0.cidr_block, +aws_subnet.gut1.cidr_block, +aws_subnet.gut2.cidr_block +] +dbSubnets = [ +aws_subnet.db0.cidr_block, +aws_subnet.db1.cidr_block, +aws_subnet.db2.cidr_block +] +} } "