From 1c93132aa57e0630148f452a7cdfbfe5af77f20b Mon Sep 17 00:00:00 2001 From: Michael Rosenfeld Date: Mon, 12 Aug 2024 13:22:23 -0500 Subject: [PATCH 1/5] Update tests for AWS and GCP, Add count functionality to flowchart, clean up provider names --- .github/workflows/build.yaml | 3 +- .github/workflows/test.yml | 21 +++- internal/flowchart.go | 90 ++++++++-------- test/aws/main.tf | 201 +++++++++++++++++++++++++++++++++++ test/{ => aws}/outputs.tf | 0 test/{ => aws}/providers.tf | 0 test/gcp/main.tf | 65 +++++++++++ test/gcp/outputs.tf | 11 ++ test/gcp/providers.tf | 13 +++ test/main.tf | 75 ------------- 10 files changed, 356 insertions(+), 123 deletions(-) create mode 100644 test/aws/main.tf rename test/{ => aws}/outputs.tf (100%) rename test/{ => aws}/providers.tf (100%) create mode 100644 test/gcp/main.tf create mode 100644 test/gcp/outputs.tf create mode 100644 test/gcp/providers.tf delete mode 100644 test/main.tf diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 45a4ecd..5017de7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,4 +1,4 @@ -name: "Build CLI and attach to GitHub release" +name: "Build CLI and Attach to GitHub Release" on: release: @@ -72,4 +72,3 @@ jobs: formula-path: Formula/t/terramaid.rb env: COMMITTER_TOKEN: ${{ secrets.COMMITTER_TOKEN }} - diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1853468..219d484 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Test +name: "Test Terramaid Outputs" on: pull_request: @@ -7,16 +7,29 @@ on: - main jobs: - test: + test_aws: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: hashicorp/setup-terraform@v3 - uses: actions/setup-go@v5 with: - go-version: '1.22.2' + go-version: "1.22.2" cache: false - run: | make build - build/terramaid -w test/ + build/terramaid -w test/aws + cat Terramaid.md + test_gcp: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: hashicorp/setup-terraform@v3 + - uses: actions/setup-go@v5 + with: + go-version: "1.22.2" + cache: false + - run: | + make build + build/terramaid -w test/gcp cat Terramaid.md diff --git a/internal/flowchart.go b/internal/flowchart.go index a0f5375..82606ea 100644 --- a/internal/flowchart.go +++ b/internal/flowchart.go @@ -11,8 +11,10 @@ import ( ) type Node struct { - ID string - Label string + ID string + Label string + Count int + Provider string } type Edge struct { @@ -21,114 +23,118 @@ type Edge struct { } type Graph struct { - Nodes []Node - Edges []Edge + Nodes []Node + Edges []Edge + NodeMap map[string]int } -// Removes unnecessary parts from the label +var labelCleaner = regexp.MustCompile(`\s*\(expand\)|\s*\(close\)|\[root\]\s*|"`) + +// CleanLabel removes unnecessary parts from the label func CleanLabel(label string) string { - re := regexp.MustCompile(`\s*\(expand\)|\s*\(close\)|\[root\]\s*|"`) - return re.ReplaceAllString(label, "") + return labelCleaner.ReplaceAllString(label, "") } -// Removes unnecessary parts from the ID +// CleanID removes unnecessary parts from the ID func CleanID(id string) string { - re := regexp.MustCompile(`\s*\(expand\)|\s*\(close\)|\[root\]\s*|"`) - return re.ReplaceAllString(id, "") + return labelCleaner.ReplaceAllString(id, "") } -// Extracts the provider for separate subgraph +// ExtractProvider extracts the provider for separate subgraph func ExtractProvider(label string) string { - if strings.Contains(label, "provider") { - parts := strings.Split(label, "/") - if len(parts) > 2 { - return parts[len(parts)-2] - } + parts := strings.Split(label, "_") + if len(parts) > 0 { + // Remove quotes from the provider name + return strings.ReplaceAll(parts[0], "\"", "") } return "" } -// Transforms the parsed graph into cleaned nodes and edges +// TransformGraph transforms the parsed graph into cleaned nodes and edges func TransformGraph(graph *gographviz.Graph) Graph { nodes := []Node{} edges := []Edge{} + nodeMap := make(map[string]int) for _, node := range graph.Nodes.Nodes { cleanedID := CleanID(node.Name) cleanedLabel := CleanLabel(node.Attrs["label"]) - if cleanedLabel != "" && !strings.Contains(cleanedLabel, "provider") { - nodes = append(nodes, Node{ID: cleanedID, Label: cleanedLabel}) + provider := ExtractProvider(cleanedLabel) + if cleanedLabel != "" { + nodeMap[cleanedLabel]++ + nodes = append(nodes, Node{ID: cleanedID, Label: cleanedLabel, Count: nodeMap[cleanedLabel], Provider: provider}) } } for _, edge := range graph.Edges.Edges { fromLabel := CleanLabel(graph.Nodes.Lookup[edge.Src].Attrs["label"]) toLabel := CleanLabel(graph.Nodes.Lookup[edge.Dst].Attrs["label"]) - if fromLabel != "" && toLabel != "" && !strings.Contains(fromLabel, "provider") && !strings.Contains(toLabel, "provider") { + if fromLabel != "" && toLabel != "" { edges = append(edges, Edge{From: CleanID(edge.Src), To: CleanID(edge.Dst)}) } } - return Graph{Nodes: nodes, Edges: edges} + return Graph{Nodes: nodes, Edges: edges, NodeMap: nodeMap} } -// Converts a gographviz graph to a Mermaid.js compatible string. +// ConvertToMermaidFlowchart converts a gographviz graph to a Mermaid.js compatible string. // It accepts a graph, direction, and an optional subgraph name. func ConvertToMermaidFlowchart(graph *gographviz.Graph, direction string, subgraphName string) (string, error) { var sb strings.Builder - // Capitalize the provider name caser := cases.Title(language.English) - // Validate the direction of the flowchart. Valid options are: TB, TD, BT, RL, LR validDirections := map[string]bool{ "TB": true, "TD": true, "BT": true, "RL": true, "LR": true, } if !validDirections[direction] { return "", fmt.Errorf("invalid direction %s: valid options are: TB, TD, BT, RL, LR", direction) } - // Start Mermaid graph definition + sb.WriteString("```mermaid\n") sb.WriteString("flowchart " + direction + "\n") - // Add subgraph for providers + if subgraphName != "" { + sb.WriteString(fmt.Sprintf("\tsubgraph %s\n", subgraphName)) + } + providerSubgraphs := make(map[string]bool) for _, n := range graph.Nodes.Nodes { - label := n.Attrs["label"] - provider := ExtractProvider(label) + provider := ExtractProvider(n.Attrs["label"]) if provider != "" && !providerSubgraphs[provider] { - sb.WriteString(fmt.Sprintf("\tsubgraph %s\n", caser.String(provider))) + sb.WriteString(fmt.Sprintf("\t\tsubgraph %s\n", caser.String(provider))) providerSubgraphs[provider] = true } } - if subgraphName != "" { - sb.WriteString(fmt.Sprintf("\tsubgraph %s\n", subgraphName)) - } - - // Iterate over nodes to add them to the Mermaid graph + nodeMap := make(map[string]int) for _, n := range graph.Nodes.Nodes { label := CleanLabel(n.Attrs["label"]) nodeName := CleanID(n.Name) - if label != "" && nodeName != "" && !strings.Contains(label, "provider") { - sb.WriteString(fmt.Sprintf("\t\t%s[\"%s\"]\n", nodeName, label)) + if label != "" && nodeName != "" { + nodeMap[label]++ + count := nodeMap[label] + if count > 1 { + sb.WriteString(fmt.Sprintf("\t\t\t%s[\"%s\\nCount: %d\"]\n", nodeName, label, count)) + } else { + sb.WriteString(fmt.Sprintf("\t\t\t%s[\"%s\"]\n", nodeName, label)) + } } } - // Iterate over edges to add them to the Mermaid graph + for range providerSubgraphs { + sb.WriteString("\t\tend\n") + } + for _, edge := range graph.Edges.Edges { srcLabel := CleanLabel(graph.Nodes.Lookup[edge.Src].Attrs["label"]) dstLabel := CleanLabel(graph.Nodes.Lookup[edge.Dst].Attrs["label"]) srcName := CleanID(edge.Src) dstName := CleanID(edge.Dst) - if srcLabel != "" && dstLabel != "" && !strings.Contains(srcLabel, "provider") && !strings.Contains(dstLabel, "provider") { + if srcLabel != "" && dstLabel != "" { sb.WriteString(fmt.Sprintf("\t\t%s --> %s\n", srcName, dstName)) } } - // Close all open subgraphs - for range providerSubgraphs { - sb.WriteString("\tend\n") - } if subgraphName != "" { sb.WriteString("\tend\n") } diff --git a/test/aws/main.tf b/test/aws/main.tf new file mode 100644 index 0000000..ab0752e --- /dev/null +++ b/test/aws/main.tf @@ -0,0 +1,201 @@ +# S3 Buckets +resource "aws_s3_bucket" "logs" { + bucket = "dev-logs" + tags = { + Name = "Dev Logs" + Environment = "dev" + } +} + +resource "aws_s3_bucket_policy" "logs_policy" { + bucket = aws_s3_bucket.logs.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = "*" + Action = ["s3:GetObject"] + Resource = ["${aws_s3_bucket.logs.arn}/*"] + }, + ] + }) +} + +resource "aws_s3_bucket" "test" { + bucket = "dev-test" + tags = { + Name = "Dev Test" + Environment = "dev" + } +} + +resource "aws_s3_bucket_policy" "test_policy" { + bucket = aws_s3_bucket.test.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = "*" + Action = ["s3:GetObject"] + Resource = ["${aws_s3_bucket.test.arn}/*"] + }, + ] + }) +} + +# EC2 Instances +resource "aws_instance" "web_server" { + count = 2 + ami = "ami-0c94855ba95c574c8" + instance_type = "t2.micro" + tags = { + Name = "Dev Web Server ${count.index + 1}" + Environment = "dev" + } +} + +resource "aws_instance" "app_server" { + ami = "ami-0c94855ba95c574c8" + instance_type = "t2.small" + tags = { + Name = "Dev App Server" + Environment = "dev" + } +} + +# RDS Database +resource "aws_db_instance" "main_db" { + identifier = "dev-main-db" + allocated_storage = 20 + storage_type = "gp2" + engine = "mysql" + engine_version = "5.7" + instance_class = "db.t2.micro" + username = "admin" + password = "password123" + parameter_group_name = "default.mysql5.7" + skip_final_snapshot = true + tags = { + Name = "Dev Main DB" + Environment = "dev" + } +} + +# VPC and Networking +resource "aws_vpc" "main" { + cidr_block = "10.0.0.0/16" + tags = { + Name = "Dev VPC" + Environment = "dev" + } +} + +resource "aws_subnet" "public" { + count = 2 + vpc_id = aws_vpc.main.id + cidr_block = "10.0.${count.index + 1}.0/24" + availability_zone = "us-west-2${["a", "b"][count.index]}" + tags = { + Name = "Dev Public Subnet ${count.index + 1}" + Environment = "dev" + } +} + +resource "aws_subnet" "private" { + count = 2 + vpc_id = aws_vpc.main.id + cidr_block = "10.0.${count.index + 3}.0/24" + availability_zone = "us-west-2${["a", "b"][count.index]}" + tags = { + Name = "Dev Private Subnet ${count.index + 1}" + Environment = "dev" + } +} + +# Security Groups +resource "aws_security_group" "web" { + name = "allow_web" + description = "Allow inbound web traffic" + vpc_id = aws_vpc.main.id + + ingress { + description = "HTTP from anywhere" + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "Dev Web SG" + Environment = "dev" + } +} + +resource "aws_security_group" "db" { + name = "allow_db" + description = "Allow inbound database traffic" + vpc_id = aws_vpc.main.id + + ingress { + description = "MySQL from web servers" + from_port = 3306 + to_port = 3306 + protocol = "tcp" + security_groups = [aws_security_group.web.id] + } + + tags = { + Name = "Dev DB SG" + Environment = "dev" + } +} + +# Load Balancer +resource "aws_lb" "web" { + name = "dev-web-lb" + internal = false + load_balancer_type = "application" + security_groups = [aws_security_group.web.id] + subnets = aws_subnet.public[*].id + + tags = { + Name = "Dev Web LB" + Environment = "dev" + } +} + +resource "aws_lb_target_group" "web" { + name = "dev-web-tg" + port = 80 + protocol = "HTTP" + vpc_id = aws_vpc.main.id +} + +resource "aws_lb_listener" "web" { + load_balancer_arn = aws_lb.web.arn + port = "80" + protocol = "HTTP" + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.web.arn + } +} + +# Attach instances to target group +resource "aws_lb_target_group_attachment" "web" { + count = 2 + target_group_arn = aws_lb_target_group.web.arn + target_id = aws_instance.web_server[count.index].id + port = 80 +} diff --git a/test/outputs.tf b/test/aws/outputs.tf similarity index 100% rename from test/outputs.tf rename to test/aws/outputs.tf diff --git a/test/providers.tf b/test/aws/providers.tf similarity index 100% rename from test/providers.tf rename to test/aws/providers.tf diff --git a/test/gcp/main.tf b/test/gcp/main.tf new file mode 100644 index 0000000..df57dfb --- /dev/null +++ b/test/gcp/main.tf @@ -0,0 +1,65 @@ +# Create a list of resource names +variable "instance_names" { + type = list(string) + default = ["instance-1", "instance-2", "instance-3"] +} + +# Create a GCP network +resource "google_compute_network" "vpc_network" { + name = "my-vpc-network" + auto_create_subnetworks = false +} + +# Create multiple subnets using a for_each loop +resource "google_compute_subnetwork" "subnet" { + count = length(var.instance_names) + + name = "subnet-${count.index + 1}" + ip_cidr_range = "10.0.${count.index}.0/24" + region = "us-central1" + network = google_compute_network.vpc_network.id +} + +# Create multiple instances using a count loop +resource "google_compute_instance" "vm_instance" { + count = length(var.instance_names) + + name = var.instance_names[count.index] + machine_type = "e2-medium" + zone = "us-central1-a" + + boot_disk { + initialize_params { + image = "debian-cloud/debian-12" + } + } + + network_interface { + network = google_compute_network.vpc_network.id + subnetwork = google_compute_subnetwork.subnet[count.index].id + } + + tags = ["web", "dev"] + + metadata = { + ssh-keys = "user:ssh-rsa XXXXXXX" + } +} + +# Create multiple firewall rules using for_each +resource "google_compute_firewall" "firewall" { + for_each = { + "allow-http" : "80" + "allow-https" : "443" + } + + name = each.key + network = google_compute_network.vpc_network.name + + allow { + protocol = "tcp" + ports = [each.value] + } + + source_ranges = ["0.0.0.0/0"] +} diff --git a/test/gcp/outputs.tf b/test/gcp/outputs.tf new file mode 100644 index 0000000..b4ef899 --- /dev/null +++ b/test/gcp/outputs.tf @@ -0,0 +1,11 @@ +output "instance_ips" { + value = google_compute_instance.vm_instance[*].network_interface[0].access_config[0].nat_ip +} + +output "subnet_ids" { + value = google_compute_subnetwork.subnet[*].id +} + +output "firewall_rule_names" { + value = google_compute_firewall.firewall[*].name +} diff --git a/test/gcp/providers.tf b/test/gcp/providers.tf new file mode 100644 index 0000000..5d07a84 --- /dev/null +++ b/test/gcp/providers.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "~> 4.0" + } + } + required_version = ">= 1.5.6" +} + +provider "google" { + region = "us-central1" +} diff --git a/test/main.tf b/test/main.tf deleted file mode 100644 index 0dfbc57..0000000 --- a/test/main.tf +++ /dev/null @@ -1,75 +0,0 @@ -resource "aws_s3_bucket" "logs" { - bucket = "dev-logs" - - tags = { - Name = "Dev Logs" - Environment = "dev" - } -} - -resource "aws_s3_bucket_policy" "logs_policy" { - bucket = aws_s3_bucket.logs.id - - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Principal = "*" - Action = ["s3:GetObject"] - Resource = ["${aws_s3_bucket.logs.arn}/*"] - }, - ] - }) -} - -resource "aws_s3_bucket" "test" { - bucket = "dev-test" - - tags = { - Name = "Dev Test" - Environment = "dev" - } -} - -resource "aws_s3_bucket_policy" "test_policy" { - bucket = aws_s3_bucket.test.id - - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Principal = "*" - Action = ["s3:GetObject"] - Resource = ["${aws_s3_bucket.test.arn}/*"] - }, - ] - }) -} - -resource "aws_instance" "example_instance" { - ami = "ami-0c94855ba95c574c8" - instance_type = "t2.micro" - - tags = { - Name = "Dev Example Instance" - Environment = "dev" - } -} - -resource "aws_db_instance" "example_db" { - allocated_storage = 20 - storage_type = "gp2" - engine = "mysql" - engine_version = "5.7" - instance_class = "db.t2.micro" - username = "foo" - password = "foobarbaz" - parameter_group_name = "default.mysql5.7" - - tags = { - Name = "Dev Example DB" - Environment = "dev" - } -} From 9d2c7887ed506ad02eaa63d51ae530e6e07d015b Mon Sep 17 00:00:00 2001 From: Michael Rosenfeld Date: Mon, 12 Aug 2024 13:29:00 -0500 Subject: [PATCH 2/5] Update docs --- README.md | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 46f974f..c216fd5 100644 --- a/README.md +++ b/README.md @@ -22,18 +22,39 @@ Terramaid transforms your Terraform resources and plans into visually appealing ```mermaid flowchart TD - subgraph Hashicorp - subgraph Terraform - aws_db_instance.example_db["aws_db_instance.example_db"] - aws_instance.example_instance["aws_instance.example_instance"] - aws_s3_bucket.logs["aws_s3_bucket.logs"] - aws_s3_bucket.test["aws_s3_bucket.test"] - aws_s3_bucket_policy.logs_policy["aws_s3_bucket_policy.logs_policy"] - aws_s3_bucket_policy.test_policy["aws_s3_bucket_policy.test_policy"] - aws_s3_bucket_policy.logs_policy --> aws_s3_bucket.logs - aws_s3_bucket_policy.test_policy --> aws_s3_bucket.test - end - end + subgraph Terraform + subgraph Aws + aws_db_instance.main_db["aws_db_instance.main_db"] + aws_instance.app_server["aws_instance.app_server"] + aws_instance.web_server["aws_instance.web_server"] + aws_lb.web["aws_lb.web"] + aws_lb_listener.web["aws_lb_listener.web"] + aws_lb_target_group.web["aws_lb_target_group.web"] + aws_lb_target_group_attachment.web["aws_lb_target_group_attachment.web"] + aws_s3_bucket.logs["aws_s3_bucket.logs"] + aws_s3_bucket.test["aws_s3_bucket.test"] + aws_s3_bucket_policy.logs_policy["aws_s3_bucket_policy.logs_policy"] + aws_s3_bucket_policy.test_policy["aws_s3_bucket_policy.test_policy"] + aws_security_group.db["aws_security_group.db"] + aws_security_group.web["aws_security_group.web"] + aws_subnet.private["aws_subnet.private"] + aws_subnet.public["aws_subnet.public"] + aws_vpc.main["aws_vpc.main"] + end + aws_lb.web --> aws_security_group.web + aws_lb.web --> aws_subnet.public + aws_lb_listener.web --> aws_lb.web + aws_lb_listener.web --> aws_lb_target_group.web + aws_lb_target_group.web --> aws_vpc.main + aws_lb_target_group_attachment.web --> aws_instance.web_server + aws_lb_target_group_attachment.web --> aws_lb_target_group.web + aws_s3_bucket_policy.logs_policy --> aws_s3_bucket.logs + aws_s3_bucket_policy.test_policy --> aws_s3_bucket.test + aws_security_group.db --> aws_security_group.web + aws_security_group.web --> aws_vpc.main + aws_subnet.private --> aws_vpc.main + aws_subnet.public --> aws_vpc.main + end ``` > [!TIP] From 2f3c04590d989460198b4e312375c2ba08dd90da Mon Sep 17 00:00:00 2001 From: Michael Rosenfeld Date: Mon, 12 Aug 2024 13:36:40 -0500 Subject: [PATCH 3/5] Add Azure Tests --- .github/workflows/test.yml | 13 ++++++ test/az/main.tf | 96 ++++++++++++++++++++++++++++++++++++++ test/az/outputs.tf | 12 +++++ test/az/providers.tf | 18 +++++++ test/az/variables.tf | 32 +++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 test/az/main.tf create mode 100644 test/az/outputs.tf create mode 100644 test/az/providers.tf create mode 100644 test/az/variables.tf diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 219d484..a08b076 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,3 +33,16 @@ jobs: make build build/terramaid -w test/gcp cat Terramaid.md + test_az: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: hashicorp/setup-terraform@v3 + - uses: actions/setup-go@v5 + with: + go-version: "1.22.2" + cache: false + - run: | + make build + build/terramaid -w test/az + cat Terramaid.md diff --git a/test/az/main.tf b/test/az/main.tf new file mode 100644 index 0000000..a9b5ea1 --- /dev/null +++ b/test/az/main.tf @@ -0,0 +1,96 @@ +# Create a resource group +resource "azurerm_resource_group" "rg" { + name = "my-resource-group" + location = var.location +} + +# Create a virtual network +resource "azurerm_virtual_network" "vnet" { + name = "my-vnet" + address_space = ["10.0.0.0/16"] + location = var.location + resource_group_name = azurerm_resource_group.rg.name +} + +# Create multiple subnets using count +resource "azurerm_subnet" "subnet" { + count = length(var.vm_names) + name = "subnet-${count.index + 1}" + resource_group_name = azurerm_resource_group.rg.name + virtual_network_name = azurerm_virtual_network.vnet.name + address_prefixes = ["10.0.${count.index}.0/24"] +} + +# Create multiple virtual machines using count +resource "azurerm_virtual_machine" "vm" { + count = length(var.vm_names) + name = var.vm_names[count.index] + resource_group_name = azurerm_resource_group.rg.name + vm_size = "Standard_DS1_v2" + location = var.location + + network_interface_ids = [ + azurerm_network_interface.nic[count.index].id, + ] + + storage_os_disk { + name = "${var.vm_names[count.index]}-osdisk" + caching = "ReadWrite" + create_option = "FromImage" + disk_size_gb = 30 + } + + storage_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2019-Datacenter" + version = "latest" + } + + os_profile { + computer_name = var.vm_names[count.index] + admin_username = "adminuser" + admin_password = "P@ssw0rd1234!" + } + + os_profile_windows_config {} +} + +# Create multiple network interfaces using count +resource "azurerm_network_interface" "nic" { + count = length(var.vm_names) + name = "nic-${count.index + 1}" + location = var.location + resource_group_name = azurerm_resource_group.rg.name + + ip_configuration { + name = "internal" + subnet_id = azurerm_subnet.subnet[count.index].id + private_ip_address_allocation = "Dynamic" + } +} + +# Create multiple security rules using for_each +resource "azurerm_network_security_group" "nsg" { + name = "my-nsg" + location = var.location + resource_group_name = azurerm_resource_group.rg.name + + security_rule { + for_each = { + "allow-http" : 80 + "allow-https" : 443 + } + + name = each.key + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_ranges = [each.value] + source_address_prefix = "*" + destination_address_prefix = "*" + } +} + diff --git a/test/az/outputs.tf b/test/az/outputs.tf new file mode 100644 index 0000000..1b49c10 --- /dev/null +++ b/test/az/outputs.tf @@ -0,0 +1,12 @@ +output "vm_public_ips" { + value = [for nic in azurerm_network_interface.nic : nic.private_ip_address] +} + +output "subnet_ids" { + value = azurerm_subnet.subnet[*].id +} + +output "nsg_name" { + value = azurerm_network_security_group.nsg.name +} + diff --git a/test/az/providers.tf b/test/az/providers.tf new file mode 100644 index 0000000..84c1216 --- /dev/null +++ b/test/az/providers.tf @@ -0,0 +1,18 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.0" + } + } + required_version = ">= 1.5.6" +} + +provider "azurerm" { + features {} + client_id = var.client_id + client_secret = var.client_secret + tenant_id = var.tenant_id + subscription_id = var.subscription_id +} + diff --git a/test/az/variables.tf b/test/az/variables.tf new file mode 100644 index 0000000..a6864c8 --- /dev/null +++ b/test/az/variables.tf @@ -0,0 +1,32 @@ +variable "vm_names" { + description = "A list of names for the virtual machines." + type = list(string) + default = ["vm-1", "vm-2", "vm-3"] +} + +variable "location" { + description = "The Azure region where resources will be created." + type = string + default = "East US" +} + +variable "client_id" { + description = "The client ID for the Azure Service Principal." + type = string +} + +variable "client_secret" { + description = "The client secret for the Azure Service Principal." + type = string +} + +variable "tenant_id" { + description = "The tenant ID for the Azure subscription." + type = string +} + +variable "subscription_id" { + description = "The subscription ID for the Azure subscription." + type = string +} + From 6c7fc9a6c0eaa519ac371a3eba682afa3b0b9209 Mon Sep 17 00:00:00 2001 From: Michael Rosenfeld Date: Mon, 12 Aug 2024 14:01:56 -0500 Subject: [PATCH 4/5] Update goreleaser and build pipelines, fix version command --- .github/workflows/build.yaml | 4 ++++ .goreleaser.yaml | 16 ++++------------ Makefile | 2 +- main.go | 4 ---- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5017de7..fbcfbc8 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -60,6 +60,10 @@ jobs: push: true tags: rosesecurity/terramaid:latest + - name: "Verify Image" + run: | + docker pull ${{ steps.build.outputs.image }}:${{ steps.build.outputs.tag}} + homebrew: name: "Bump Homebrew Formula" runs-on: ubuntu-latest diff --git a/.goreleaser.yaml b/.goreleaser.yaml index e1a77aa..c8565b6 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -9,24 +9,16 @@ before: builds: - env: - CGO_ENABLED=0 - ldflags: -s -w -X main.version={{ .Version }} + ldflags: + - '-s -w -X "github.com/rosesecurity/Terramaid/cmd.Version={{.Version}}"' goos: - linux - windows - darwin archives: - - format: tar.gz - name_template: >- - {{ .ProjectName }}_ - {{- title .Os }}_ - {{- if eq .Arch "amd64" }}x86_64 - {{- else if eq .Arch "386" }}i386 - {{- else }}{{ .Arch }}{{ end }} - {{- if .Arm }}v{{ .Arm }}{{ end }} - format_overrides: - - goos: windows - format: zip + - format: binary + name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' changelog: sort: asc diff --git a/Makefile b/Makefile index ce15041..0d63d3d 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ fmt: ## Format Go files gofumpt -w . build: ## Build Terramaid - $(GO) build -ldflags="-s -w" -o build/$(BINARY_NAME) main.go + env $(if $(GOOS),GOOS=$(GOOS)) $(if $(GOARCH),GOARCH=$(GOARCH)) $(GO) build -o build/$(BINARY_NAME) -ldflags "-X 'github.com/rosesecurity/Terramaid/cmd.Version=${VERSION}'" main.go install: ## Install dependencies $(GO) install ./...@latest diff --git a/main.go b/main.go index 2cbd10e..8b70d84 100644 --- a/main.go +++ b/main.go @@ -5,11 +5,7 @@ import ( u "github.com/RoseSecurity/terramaid/pkg/utils" ) -var version string - func main() { - cmd.Version = version - if err := cmd.Execute(); err != nil { u.LogErrorAndExit(err) } From 5cfede655853fccc94f36f9d282c567403d4654d Mon Sep 17 00:00:00 2001 From: Michael Rosenfeld Date: Mon, 12 Aug 2024 14:05:30 -0500 Subject: [PATCH 5/5] Keep TARs for Homebrew --- .goreleaser.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index c8565b6..6e68c1a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -17,8 +17,17 @@ builds: - darwin archives: - - format: binary - name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' + - format: tar.gz + name_template: >- + {{ .ProjectName }}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} + format_overrides: + - goos: windows + format: zip changelog: sort: asc