From 6315d9908bde546bd8ca03827921bb4ed98290f9 Mon Sep 17 00:00:00 2001 From: Denis-Florin Rendler Date: Sun, 12 Jan 2025 08:01:57 +0200 Subject: [PATCH 1/3] feat: add github workflows and changelog config --- .chglog/CHANGELOG.tpl.md | 38 ++++++++++++++ .chglog/config.yml | 30 +++++++++++ .github/ISSUE_TEMPLATE/00-bug-request.md | 25 +++++++++ .github/ISSUE_TEMPLATE/01-feature-request.md | 18 +++++++ .github/workflows/changelog.yml | 51 ++++++++++++++++++ .github/workflows/release.yml | 43 +++++++++++++++ .github/workflows/tflint.yml | 55 ++++++++++++++++++++ .tflint.hcl | 3 ++ 8 files changed, 263 insertions(+) create mode 100755 .chglog/CHANGELOG.tpl.md create mode 100755 .chglog/config.yml create mode 100644 .github/ISSUE_TEMPLATE/00-bug-request.md create mode 100644 .github/ISSUE_TEMPLATE/01-feature-request.md create mode 100644 .github/workflows/changelog.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tflint.yml create mode 100644 .tflint.hcl diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100755 index 0000000..718267a --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,38 @@ +{{ range .Versions }} +Release {{ .Tag.Name }} +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }}) + +{{ range .CommitGroups -}} +### {{ .Title }} + +{{ range .Commits -}} +* {{ .Subject }} +{{ end }} +{{ end -}} + +{{- if .RevertCommits -}} +### Reverts + +{{ range .RevertCommits -}} +* {{ .Revert.Header }} +{{ end }} +{{ end -}} + +{{- if .MergeCommits -}} +### Pull Requests + +{{ range .MergeCommits -}} +* {{ .Header }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} + +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} \ No newline at end of file diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100755 index 0000000..723ced5 --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,30 @@ +style: github +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://github.com/rendler-denis/tf-mod-netbox +options: + commits: + filters: + Type: + - feat + - fix + - perf + - refactor + - docs + commit_groups: + title_maps: + feat: Features + fix: Bug Fixes + perf: Performance Improvements + refactor: Code Refactoring + docs: Documentation + header: + pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" + pattern_maps: + - Type + - Scope + - Subject + notes: + keywords: + - BREAKING CHANGE diff --git a/.github/ISSUE_TEMPLATE/00-bug-request.md b/.github/ISSUE_TEMPLATE/00-bug-request.md new file mode 100644 index 0000000..c3130ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/00-bug-request.md @@ -0,0 +1,25 @@ +--- +name: Bug Issue +about: Use this template for reporting a bug +labels: 'type:bug' + +--- + +Please first make sure that this is a bug in the module and not an issue +with the provider used. + +**System information** +- OS Platform and Distribution (e.g., Linux Ubuntu 16.04): +- Terraform/OpenTofu version: +- Provider name and version: + +**Describe the current behavior** + +**Describe the expected behavior** + +**Steps to reproduce the issue** + +**Other info / logs** +Include any logs or source code that would be helpful to +diagnose the problem. +Since this is an open forum please make sure to obfuscate any sensitive information. diff --git a/.github/ISSUE_TEMPLATE/01-feature-request.md b/.github/ISSUE_TEMPLATE/01-feature-request.md new file mode 100644 index 0000000..a383087 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01-feature-request.md @@ -0,0 +1,18 @@ +--- +name: Feature Request +about: Use this template for raising a feature request +labels: 'type:feature' + +--- + +Please make sure that this is a feature request. + +**Basic information** +- Terraform/OpenTofu version you are using: +- Are you willing to develop and contribute the feature (Yes/No): + +**Describe the feature and the current behavior/state.** + +**Who will benefit with this feature?** + +**Any Other info.** diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000..8b65e8e --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,51 @@ +name: Module Changelog + +on: + push: + branches: [ main ] + +# it is required to be able to push back to the repository +permissions: + contents: write + +jobs: + create-changelog: + runs-on: ubuntu-latest + # Add this condition to prevent an infinite loop + if: ${{ !contains(github.event.head_commit.message, 'Add changelog') }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Extract version from PR title + id: version + run: | + PR_TITLE="${{ github.event.head_commit.message }}" + echo "Processing PR title: $PR_TITLE" + + # Take only the first version number found + VERSION=$(echo "$PR_TITLE" | grep -oE "version: [0-9]+\.[0-9]+\.[0-9]+" | head -n 1 | cut -d' ' -f2) + + if [ ! -z "$VERSION" ]; then + echo "Found version: $VERSION" + echo "version=$VERSION" >> $GITHUB_OUTPUT + else + echo "No version found in PR title" + exit 0 + fi + + - name: Generate changelog + if: steps.version.outputs.version != '' + run: "docker run --rm -v ${GITHUB_WORKSPACE}:/workdir -w /workdir quay.io/git-chglog/git-chglog:latest --next-tag ${{ steps.version.outputs.version }} -o CHANGELOG.md" + + - name: Create commit with changelog + if: steps.version.outputs.version != '' + run: | + git config user.name "Denis Rendler (GitHub Actions)" + git config user.email "connect@rendler.net" + git add CHANGELOG.md + git commit -m "Add changelog" + git push origin main diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..fea2498 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: Create Release Package + +on: + push: + tags: + - '*' # Triggers on version tags like 1.0.0 + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write # Needed for creating releases + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetches complete history for accurate changelog + + # Create release archive + - name: Create release archive + run: | + # Exclude unnecessary files from the archive + mkdir release && \ + tar --exclude='.git' \ + --exclude='.github' \ + --exclude='test' \ + --exclude='.gitignore' \ + --exclude='.chglog' \ + --exclude='release' \ + -czf release/release-${{ github.ref_name }}.tar.gz . + + # Create the GitHub release + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ github.ref_name }} + name: Release ${{ github.ref_name }} + body_path: CHANGELOG.md + files: | + release-${{ github.ref_name }}.tar.gz + draft: false + prerelease: false diff --git a/.github/workflows/tflint.yml b/.github/workflows/tflint.yml new file mode 100644 index 0000000..f71bd99 --- /dev/null +++ b/.github/workflows/tflint.yml @@ -0,0 +1,55 @@ +name: 'TFLint Check' + +on: + push: + paths: + - '**.tf' + - '.github/workflows/tflint.yml' + pull_request: + paths: + - '**.tf' + - '.github/workflows/tflint.yml' + +jobs: + tflint: + name: 'TFLint' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup TFLint + uses: terraform-linters/setup-tflint@v4 + with: + tflint_version: latest + + - name: Initialize TFLint + run: tflint --init + + - name: Find Terraform directories + id: find_dirs + run: | + echo "terraform_dirs<> $GITHUB_OUTPUT + find . -type f -name "*.tf" -exec dirname {} \; | sort -u >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Run TFLint recursively + run: | + EXIT_CODE=0 + while IFS= read -r dir; do + echo "Running TFLint in directory: $dir" + pushd "$dir" > /dev/null + + # Initialize TFLint in each directory + tflint --init -c ../.tflint.hcl + + # Run TFLint and store its exit code + if ! tflint --format compact; then + EXIT_CODE=1 + fi + + popd > /dev/null + done <<< "$(echo "${{ steps.find_dirs.outputs.terraform_dirs }}")" + + exit $EXIT_CODE diff --git a/.tflint.hcl b/.tflint.hcl new file mode 100644 index 0000000..8be8995 --- /dev/null +++ b/.tflint.hcl @@ -0,0 +1,3 @@ + +// disable terraform required version +rule "terraform_required_version" { enabled = false } \ No newline at end of file From e509cb101e3831e5800ac3de28f46a3d9e1ad998 Mon Sep 17 00:00:00 2001 From: Denis-Florin Rendler Date: Sun, 12 Jan 2025 08:02:18 +0200 Subject: [PATCH 2/3] fix: after tflint --- netbox-customization/main.tf | 7 ++-- netbox-customization/outputs.tf | 2 +- netbox-data-org/main.tf | 23 +++++------ netbox-data-org/outputs.tf | 10 ++--- netbox-devices/main.tf | 31 +++++++-------- netbox-devices/variables.tf | 36 +++++++++--------- netbox-ipam/main.tf | 5 ++- netbox-ipam/variables.tf | 67 +++++++++++++++------------------ netbox-organization/main.tf | 3 +- netbox-primary-ip/main.tf | 3 +- netbox-primary-ip/variables.tf | 4 +- netbox-racks/main.tf | 5 ++- netbox-virtualization/main.tf | 3 +- 13 files changed, 100 insertions(+), 99 deletions(-) diff --git a/netbox-customization/main.tf b/netbox-customization/main.tf index 3c78389..796b4ed 100644 --- a/netbox-customization/main.tf +++ b/netbox-customization/main.tf @@ -6,7 +6,8 @@ terraform { required_providers { netbox = { - source = "e-breuninger/netbox" + source = "e-breuninger/netbox" + version = "= 3.9.2" } } } @@ -57,14 +58,14 @@ resource "netbox_custom_field" "custom_fields" { resource "netbox_tag" "custom_tags" { for_each = var.custom_tags - name = each.value.name + name = each.value.name color_hex = try(each.value.color_hex, "9e9e9e") slug = try(each.value.slug, null) description = try(each.value.description, null) lifecycle { - ignore_changes = [ tags ] + ignore_changes = [tags] } } diff --git a/netbox-customization/outputs.tf b/netbox-customization/outputs.tf index 6c1ee59..0bd823f 100644 --- a/netbox-customization/outputs.tf +++ b/netbox-customization/outputs.tf @@ -5,7 +5,7 @@ output "managed_customizations" { description = "Managed customizations" - value = { + value = { custom_fields = { for custom_field in netbox_custom_field.custom_fields : custom_field.name => { diff --git a/netbox-data-org/main.tf b/netbox-data-org/main.tf index 4e5c585..dc5d35a 100644 --- a/netbox-data-org/main.tf +++ b/netbox-data-org/main.tf @@ -6,7 +6,8 @@ terraform { required_providers { netbox = { - source = "e-breuninger/netbox" + source = "e-breuninger/netbox" + version = "=3.9.2" } } } @@ -18,25 +19,25 @@ data "netbox_site" "sites" { } data "netbox_tenant" "tenants" { - for_each = toset(var.tenants) - name = each.value + for_each = toset(var.tenants) + name = each.value } data "netbox_location" "locations" { - for_each = toset(var.locations) - name = each.value + for_each = toset(var.locations) + name = each.value } data "netbox_region" "regions" { - for_each = toset(var.regions) + for_each = toset(var.regions) - filter { - name = each.value - } + filter { + name = each.value + } } data "netbox_site_group" "site_groups" { - for_each = toset(var.site_groups) - name = each.value + for_each = toset(var.site_groups) + name = each.value } # ######## END LOOKUPS ############ diff --git a/netbox-data-org/outputs.tf b/netbox-data-org/outputs.tf index 48e348f..b3f194e 100644 --- a/netbox-data-org/outputs.tf +++ b/netbox-data-org/outputs.tf @@ -5,35 +5,35 @@ output "sites_map" { description = "Map of site names to their IDs" - value = { + value = { for name, site in data.netbox_site.sites : name => site.id } } output "tenants_map" { description = "Map of tenant names to their IDs" - value = { + value = { for name, tenant in data.netbox_tenant.tenants : name => tenant.id } } output "locations_map" { description = "Map of location names to their IDs" - value = { + value = { for name, location in data.netbox_location.locations : name => location.id } } output "regions_map" { description = "Map of region names to their IDs" - value = { + value = { for name, region in data.netbox_region.regions : name => region.id } } output "site_groups_map" { description = "Map of site group names to their IDs" - value = { + value = { for name, site_group in data.netbox_site_group.site_groups : name => site_group.id } } \ No newline at end of file diff --git a/netbox-devices/main.tf b/netbox-devices/main.tf index f05c8c4..e6afecb 100644 --- a/netbox-devices/main.tf +++ b/netbox-devices/main.tf @@ -6,7 +6,8 @@ terraform { required_providers { netbox = { - source = "e-breuninger/netbox" + source = "e-breuninger/netbox" + version = "=3.9.2" } } } @@ -44,7 +45,7 @@ resource "netbox_device_role" "dev_roles" { vm_role = try(each.value.vm_role, null) lifecycle { - ignore_changes = [ tags ] + ignore_changes = [tags] } } @@ -67,7 +68,7 @@ resource "netbox_device_type" "dev_types" { part_number = try(each.value.part_number, null) lifecycle { - ignore_changes = [ tags ] + ignore_changes = [tags] } } @@ -105,12 +106,12 @@ resource "netbox_device" "device-info" { status = try(each.value.status, null) lifecycle { - ignore_changes = [ tags, comments ] + ignore_changes = [tags, comments] } } resource "netbox_device_interface" "dev_interfaces" { - for_each = merge([ + for_each = merge([ for device_key, device in var.devices : { for iface in device.interfaces : "${device.name}_${iface.name}" => merge(iface, { device = device_key, device_name = device.name }) } if device.interfaces != null @@ -120,16 +121,16 @@ resource "netbox_device_interface" "dev_interfaces" { device_id = netbox_device.device-info[each.value.device].id type = each.value.type - description = try(each.value.description, null) - enabled = try(each.value.enabled, null) - label = try(each.value.label, null) - mac_address = try(each.value.mac_address, null) - mgmtonly = try(each.value.mgmtonly, false) - mode = try(each.value.mode, "access") - mtu = try(each.value.mtu, 1500) - speed = try(each.value.speed, null) - tagged_vlans = try(each.value.tagged_vlans, null) - untagged_vlan = try(each.value.untagged_vlan, null) + description = try(each.value.description, null) + enabled = try(each.value.enabled, null) + label = try(each.value.label, null) + mac_address = try(each.value.mac_address, null) + mgmtonly = try(each.value.mgmtonly, false) + mode = try(each.value.mode, "access") + mtu = try(each.value.mtu, 1500) + speed = try(each.value.speed, null) + tagged_vlans = try(each.value.tagged_vlans, null) + untagged_vlan = try(each.value.untagged_vlan, null) lifecycle { ignore_changes = [tags, parent_device_interface_id, lag_device_interface_id] diff --git a/netbox-devices/variables.tf b/netbox-devices/variables.tf index 270f8a0..252c33b 100644 --- a/netbox-devices/variables.tf +++ b/netbox-devices/variables.tf @@ -73,18 +73,18 @@ variable "devices" { status = optional(string) interfaces = optional(list(object({ - name = string - type = string - description = optional(string) - enabled = optional(bool, true) - label = optional(string) - mac_address = optional(string) - mgmt_only = optional(bool) - mode = optional(string, "access") - mtu = optional(number) - speed = optional(number) - untagged_vlan = optional(number) - tagged_vlans = optional(list(number)) + name = string + type = string + description = optional(string) + enabled = optional(bool, true) + label = optional(string) + mac_address = optional(string) + mgmt_only = optional(bool) + mode = optional(string, "access") + mtu = optional(number) + speed = optional(number) + untagged_vlan = optional(number) + tagged_vlans = optional(list(number)) }))) })) default = {} @@ -92,18 +92,18 @@ variable "devices" { variable "site_id_map" { description = "Mapping of site names to IDs" - type = map(number) - default = {} + type = map(number) + default = {} } variable "location_id_map" { description = "Mapping of location names to IDs" - type = map(number) - default = {} + type = map(number) + default = {} } variable "tenant_id_map" { description = "Mapping of tenant names to IDs" - type = map(number) - default = {} + type = map(number) + default = {} } diff --git a/netbox-ipam/main.tf b/netbox-ipam/main.tf index 0172961..dc9ae42 100644 --- a/netbox-ipam/main.tf +++ b/netbox-ipam/main.tf @@ -6,7 +6,8 @@ terraform { required_providers { netbox = { - source = "e-breuninger/netbox" + source = "e-breuninger/netbox" + version = "=3.9.2" } } } @@ -86,7 +87,7 @@ resource "netbox_vlan_group" "vlan_groups" { // TODO: find way to add cluster and clustergroup without coupling to virtualization module # "virtualization.cluster" = var.cluster_id_map[each.value.scope] # "virtualization.clustergroup" = var.cluster_group_id_map[each.value.scope] - }, each.value.scope_type) + }, each.value.scope_type, null) lifecycle { ignore_changes = [tags] diff --git a/netbox-ipam/variables.tf b/netbox-ipam/variables.tf index 6bc0ea2..ba95471 100644 --- a/netbox-ipam/variables.tf +++ b/netbox-ipam/variables.tf @@ -177,37 +177,36 @@ variable "ip_addresses" { } } -variable "services" { - description = "List of services running on devices or virtual machines" - type = map(object({ - name = string - protocol = string - custom_fields = optional(map(string)) - description = optional(string) - device_id = optional(number) - port = optional(number) - ports = optional(list(number)) - device_vm = optional(string) - })) - default = {} - - validation { - condition = alltrue([ - for service in var.services : - contains(["tcp", "udp", "icmp", "icmpv6", "ipv6-icmp"], service.protocol) - ]) - error_message = "protocol must be one of: tcp, udp, icmp, icmpv6, ipv6-icmp" - } - - validation { - condition = alltrue([ - for service in var.services : - service.port != null || service.ports != null - ]) - error_message = "Either port or ports must be set" - } - -} +# variable "services" { +# description = "List of services running on devices or virtual machines" +# type = map(object({ +# name = string +# protocol = string +# custom_fields = optional(map(string)) +# description = optional(string) +# device_id = optional(number) +# port = optional(number) +# ports = optional(list(number)) +# device_vm = optional(string) +# })) +# default = {} + +# validation { +# condition = alltrue([ +# for service in var.services : +# contains(["tcp", "udp", "icmp", "icmpv6", "ipv6-icmp"], service.protocol) +# ]) +# error_message = "protocol must be one of: tcp, udp, icmp, icmpv6, ipv6-icmp" +# } + +# validation { +# condition = alltrue([ +# for service in var.services : +# service.port != null || service.ports != null +# ]) +# error_message = "Either port or ports must be set" +# } +# } variable "site_id_map" { description = "Mapping of site names to IDs" @@ -238,9 +237,3 @@ variable "region_id_map" { type = map(number) default = {} } - -variable "rack_id_map" { - description = "Mapping of rack names to IDs" - type = map(number) - default = {} -} diff --git a/netbox-organization/main.tf b/netbox-organization/main.tf index 5bbc509..2f20385 100644 --- a/netbox-organization/main.tf +++ b/netbox-organization/main.tf @@ -6,7 +6,8 @@ terraform { required_providers { netbox = { - source = "e-breuninger/netbox" + source = "e-breuninger/netbox" + version = "=3.9.2" } } } diff --git a/netbox-primary-ip/main.tf b/netbox-primary-ip/main.tf index b9aef8d..c2df2e1 100644 --- a/netbox-primary-ip/main.tf +++ b/netbox-primary-ip/main.tf @@ -6,7 +6,8 @@ terraform { required_providers { netbox = { - source = "e-breuninger/netbox" + source = "e-breuninger/netbox" + version = "=3.9.2" } } } diff --git a/netbox-primary-ip/variables.tf b/netbox-primary-ip/variables.tf index 668b418..57b9f00 100644 --- a/netbox-primary-ip/variables.tf +++ b/netbox-primary-ip/variables.tf @@ -5,14 +5,14 @@ variable "devices" { description = "Map of devices with their primary IP addresses" - type = map(string) + type = map(string) default = {} } variable "vms" { description = "Map of virtual machines with their primary IP addresses" - type = map(string) + type = map(string) default = {} } diff --git a/netbox-racks/main.tf b/netbox-racks/main.tf index 98c27fa..53d42b8 100644 --- a/netbox-racks/main.tf +++ b/netbox-racks/main.tf @@ -6,7 +6,8 @@ terraform { required_providers { netbox = { - source = "e-breuninger/netbox" + source = "e-breuninger/netbox" + version = "=3.9.2" } } } @@ -50,7 +51,7 @@ resource "netbox_rack" "racks" { weight_unit = try(each.value.weight_unit, "kg") lifecycle { - ignore_changes = [ tags, comments, type ] + ignore_changes = [tags, comments, type] } } diff --git a/netbox-virtualization/main.tf b/netbox-virtualization/main.tf index 88b5836..b53b9cf 100644 --- a/netbox-virtualization/main.tf +++ b/netbox-virtualization/main.tf @@ -6,7 +6,8 @@ terraform { required_providers { netbox = { - source = "e-breuninger/netbox" + source = "e-breuninger/netbox" + version = "=3.9.2" } } } From d29b9d540d5de93aa5d33f2644cbbbbb607e920e Mon Sep 17 00:00:00 2001 From: Denis-Florin Rendler Date: Sun, 12 Jan 2025 08:04:43 +0200 Subject: [PATCH 3/3] fix: tflint config workflow --- .github/workflows/tflint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tflint.yml b/.github/workflows/tflint.yml index f71bd99..51581a5 100644 --- a/.github/workflows/tflint.yml +++ b/.github/workflows/tflint.yml @@ -42,10 +42,10 @@ jobs: pushd "$dir" > /dev/null # Initialize TFLint in each directory - tflint --init -c ../.tflint.hcl + tflint --init # Run TFLint and store its exit code - if ! tflint --format compact; then + if ! tflint --format compact -c ../.tflint.hcl; then EXIT_CODE=1 fi