[
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\nHashiCorp Community Guidelines apply to you when interacting with the community\nhere on GitHub and contributing code.\n\nPlease read the full text at <https://www.hashicorp.com/community-guidelines>\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "# Issue Reporting Guide\n\nHi there,\n\nThank you for opening an issue. Please note that we try to keep the Terraform\nissue tracker reserved for bug reports and feature requests. For general usage\nquestions, please see: <https://www.terraform.io/community.html>.\n\n## Terraform Version\n\nRun `terraform -v` to show the version. If you are not running the latest\nversion of Terraform, please upgrade because your issue may have already been\nfixed.\n\n## Affected Resource(s)\n\nPlease list the resources as a list, for example:\n\n- opc_instance\n- opc_storage_volume\n\nIf this issue appears to affect multiple resources, it may be an issue with\nTerraform's core, so please mention this.\n\n## Terraform Configuration Files\n\n```hcl\n# Copy-paste your Terraform configurations here - for large Terraform configs,\n# please use a service like Dropbox and share a link to the ZIP file. For\n# security, you can also encrypt the files using our GPG public key.\n```\n\n## Debug Output\n\nPlease provide a link to a GitHub Gist containing the complete debug output:\n<https://www.terraform.io/docs/internals/debugging.html>. Please do NOT paste\nthe debug output in the issue; just paste a link to the Gist.\n\n## Panic Output\n\nIf Terraform produced a panic, please provide a link to a GitHub Gist containing\nthe output of the `crash.log`.\n\n## Expected Behavior\n\nWhat should have happened?\n\n## Actual Behavior\n\nWhat actually happened?\n\n## Steps to Reproduce\n\nPlease list the steps required to reproduce the issue, for example:\n\n1. `terraform apply`\n\n## Important Factoids\n\nAre there anything atypical about your accounts that we should know? For\nexample: Running in EC2 Classic? Custom version of OpenStack? Tight ACLs?\n\n## References\n\nAre there any other GitHub issues (open or closed) or Pull Requests that should\nbe linked here? For example:\n\n- GH-1234\n"
  },
  {
    "path": ".github/allowed-subcategories.txt",
    "content": "Authentication\nCircuits\nData Center Inventory Management (DCIM)\nExtras\nIP Address Management (IPAM)\nTenancy\nVirtualization\nVPN Tunnels\nWireless\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "---\nversion: 2\nupdates:\n  - package-ecosystem: gomod\n    directory: \"/\"\n    schedule:\n      interval: daily\n      time: \"04:00\"\n    open-pull-requests-limit: 10\n  - package-ecosystem: github-actions\n    directory: \"/\"\n    schedule:\n      interval: daily\n      time: \"04:00\"\n    open-pull-requests-limit: 10\n"
  },
  {
    "path": ".github/workflows/check-allowed-subcategories.yml",
    "content": "---\nname: check-allowed-subcategories\non: [push, pull_request]\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n      - name: check-allowed-subcategories\n        run: bash scripts/allowed_subcategories.sh\n"
  },
  {
    "path": ".github/workflows/ci-testing.yml",
    "content": "---\nname: ci-testing\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n  workflow_dispatch:\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - name: Set up Go\n        uses: actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n      - name: test\n        run: make test\n\n  testacc:\n    runs-on: ubuntu-22.04\n    strategy:\n      fail-fast: false\n      matrix:\n        netbox-version:\n          - v4.3.0\n          # - v4.3.1 # with this version, we get {\"scope\":[\"Please select a site.\"]} for prefixes\n          - v4.3.2\n          - v4.3.3\n          - v4.3.4\n          - v4.3.5\n          - v4.3.6\n          - v4.3.7\n          - v4.4.0\n          - v4.4.1\n          - v4.4.2\n          # - v4.4.3 # this version cannot be spun up for testing due to TypeError: issubclass() arg 1 must be a class\n          - v4.4.4\n          - v4.4.5\n          - v4.4.6\n          - v4.4.7\n          - v4.4.8\n          - v4.4.9\n          - v4.4.10\n    steps:\n      - uses: actions/checkout@v6\n      - name: Set up Go\n        uses: actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n      - name: testacc\n        run: make -e testacc\n        env:\n          NETBOX_VERSION: ${{ matrix.netbox-version }}\n"
  },
  {
    "path": ".github/workflows/ensure-docs-examples.yml",
    "content": "---\nname: ensure-docs-examples\non: [push, pull_request]\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n      - name: ensure-docs-examples\n        run: bash scripts/ensure_docs_examples.sh\n"
  },
  {
    "path": ".github/workflows/golangci-lint.yml",
    "content": "---\nname: linting\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n\npermissions:\n  contents: read\n  # Optional: allow read access to pull request. Use with `only-new-issues` option.\n  # pull-requests: read\n\njobs:\n  golangci:\n    name: golangci\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n          cache: false\n      - name: golangci-lint\n        uses: golangci/golangci-lint-action@v9.2.0\n        with:\n          version: v2.11\n\n  doc-check:\n    name: docs check\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n      - run: |\n          make docs\n          git add --intent-to-add --all\n          git diff --exit-code || (echo \"::error title=Doc generation changes detected::Please update the docs and commit them to the PR\" && exit 1)\n"
  },
  {
    "path": ".github/workflows/pre-commit.yml",
    "content": "---\nname: pre-commit\n\non:\n  pull_request:\n  push:\n    branches: [master]\n\npermissions: read-all\n\njobs:\n  pre-commit:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Setup pre-commit\n        run: python -m pip install pre-commit\n\n      - name: Run pre-commit checks\n        uses: pre-commit/action@v3.0.1\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "---\n# This GitHub action can publish assets for release when a tag is created.\n# Currently its setup to run on any tag that matches the pattern \"v*\" (ie. v0.1.0).\n#\n# This uses an action (paultyng/ghaction-import-gpg) that assumes you set your\n# private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE`\n# secret. If you would rather own your own GPG handling, please fork this action\n# or use an alternative one for key handling.\n#\n# You will need to pass the `--batch` flag to `gpg` in your signing step\n# in `goreleaser` to indicate this is being used in a non-interactive mode.\n#\nname: release\non:\n  push:\n    tags:\n      - \"v*\"\njobs:\n  goreleaser:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n      - name: Unshallow\n        run: git fetch --prune --unshallow\n      - name: Set up Go\n        uses: actions/setup-go@v6\n        with:\n          go-version-file: go.mod\n      - name: Import GPG key\n        id: import_gpg\n        uses: crazy-max/ghaction-import-gpg@v7.0.0\n        with:\n          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}\n          passphrase: ${{ secrets.PASSPHRASE }}\n      - name: Run GoReleaser\n        uses: goreleaser/goreleaser-action@v7.2.1\n        with:\n          version: latest\n          args: release --clean\n        env:\n          GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "*.dll\n*.exe\n.envrc\n.DS_Store\nexample.tf\nterraform.tfplan\nterraform.tfstate\nbin/\ndist/\nmodules-dev/\n/pkg/\nwebsite/.vagrant\nwebsite/.bundle\nwebsite/build\nwebsite/node_modules\n.vagrant/\n*.backup\n./*.tfstate\n.terraform/\n*.log\n*.bak\n*~\n.*.swp\n.idea\n*.iml\n*.test\n*.iml\n\nwebsite/vendor\n\n# Test exclusions\n!command/test-fixtures/**/*.tfstate\n!command/test-fixtures/**/.terraform/\n\n# Keep windows files with windows line endings\n*.winfile eol=crlf\n\n# Locally compiled provider\nterraform-provider-netbox\n"
  },
  {
    "path": ".golangci.yml",
    "content": "---\nversion: \"2\"\nlinters:\n  enable:\n    - staticcheck\n    - whitespace\n  disable:\n    - errcheck\n  exclusions:\n    generated: lax\n    presets:\n      - comments\n      - common-false-positives\n      - legacy\n      - std-error-handling\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\nformatters:\n  exclusions:\n    generated: lax\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\n"
  },
  {
    "path": ".goreleaser.yml",
    "content": "---\n# Visit https://goreleaser.com for documentation on how to customize this\n# behavior.\n\nversion: 2\n\nbefore:\n  hooks:\n    # this is just an example and not a requirement for provider building/publishing\n    - go mod tidy\n\nbuilds:\n  - env:\n      # goreleaser does not work with CGO, it could also complicate\n      # usage by users in CI/CD systems like Terraform Cloud where\n      # they are unable to install libraries.\n      - CGO_ENABLED=0\n    mod_timestamp: \"{{ .CommitTimestamp }}\"\n    flags:\n      - -trimpath\n    ldflags:\n      - \"-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}\"\n    goos:\n      # - freebsd\n      - windows\n      - linux\n      - darwin\n    goarch:\n      - amd64\n      - \"386\"\n      # - arm\n      - arm64\n    ignore:\n      - goos: darwin\n        goarch: \"386\"\n    binary: \"{{ .ProjectName }}_v{{ .Version }}\"\n\narchives:\n  - format: zip\n    name_template: \"{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}\"\n\nchecksum:\n  name_template: \"{{ .ProjectName }}_{{ .Version }}_SHA256SUMS\"\n  algorithm: sha256\n\nsigns:\n  - artifacts: checksum\n    args:\n      # if you are using this is a GitHub action or some other automated pipeline, you\n      # need to pass the batch flag to indicate its not interactive.\n      - \"--batch\"\n      - \"--local-user\"\n      - \"{{ .Env.GPG_FINGERPRINT }}\" # set this environment variable for your signing key\n      - \"--output\"\n      - \"${signature}\"\n      - \"--detach-sign\"\n      - \"${artifact}\"\n\nrelease:\n  # If you want to manually examine the release before its live, uncomment this line:\n  # draft: true\n\nchangelog:\n  disable: true\n"
  },
  {
    "path": ".markdownlint.yaml",
    "content": "---\nMD013: false\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "---\ndefault_stages:\n  - commit\n\ndefault_install_hook_types:\n  - commit-msg\n  - pre-commit\n  - prepare-commit-msg\n\nexclude: \"^docs/|^CHANGELOG.md$\"\n\nrepos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: \"v4.5.0\"\n    hooks:\n      - id: check-added-large-files\n      - id: check-case-conflict\n      - id: check-executables-have-shebangs\n      - id: check-json\n      - id: check-merge-conflict\n      - id: check-shebang-scripts-are-executable\n      - id: check-symlinks\n      - id: check-toml\n      - id: check-vcs-permalinks\n      - id: check-xml\n      - id: check-yaml\n      - id: destroyed-symlinks\n      - id: detect-private-key\n      - id: end-of-file-fixer\n      - id: fix-byte-order-marker\n      - id: forbid-new-submodules\n      - id: trailing-whitespace\n\n  - repo: https://github.com/pre-commit/mirrors-prettier\n    rev: \"v3.1.0\"\n    hooks:\n      - id: prettier\n        exclude: \"^project/\"\n\n  - repo: https://github.com/igorshubovych/markdownlint-cli\n    rev: \"v0.38.0\"\n    hooks:\n      - id: markdownlint-fix\n        name: markdownlint\n\n  - repo: https://github.com/adrienverge/yamllint\n    rev: \"v1.33.0\"\n    hooks:\n      - id: yamllint\n        entry: yamllint --strict\n\n  - repo: https://github.com/pecigonzalo/pre-commit-shfmt\n    rev: \"v2.1.0\"\n    hooks:\n      - id: shell-fmt-go\n\n  - repo: https://github.com/shellcheck-py/shellcheck-py\n    rev: \"v0.9.0.6\"\n    hooks:\n      - id: shellcheck\n\n  - repo: https://github.com/rhysd/actionlint\n    rev: \"v1.6.26\"\n    hooks:\n      - id: actionlint\n"
  },
  {
    "path": ".prettierignore",
    "content": "# ignore generated documentation\ndocs/\n"
  },
  {
    "path": ".terraform-registry",
    "content": "Request: change owner to fbreckle\nRegistry Link: https://registry.terraform.io/providers/e-breuninger/netbox\nRequest by: fabian.breckle@breuninger.de\n"
  },
  {
    "path": ".yamllint.yaml",
    "content": "---\nextends: default\n\nrules:\n  comments:\n    min-spaces-from-content: 1\n  line-length: disable\n  truthy:\n    allowed-values: [\"true\", \"false\"]\n    check-keys: false\n  comments-indentation:\n    ignore: |\n      .goreleaser.yml\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## 5.3.0 (April 9th, 2026)\n\nENHANCEMENTS\n\n* provider: Now supports using [v2 API tokens](https://netboxlabs.com/docs/netbox/integrations/rest-api/#authenticating-to-the-api) ([#862](https://github.com/e-breuninger/terraform-provider-netbox/pull/862) by [@MrKeiKun](https://github.com/MrKeiKun))\n  Note that this is a NetBox v4.5 feature. This provider does not officially support v4.5 versions yet.\n* **New Resource:** `netbox_wireless_lan` ([#859](https://github.com/e-breuninger/terraform-provider-netbox/pull/859) by [@JonasKop](https://github.com/JonasKop))\n* **New Resource:** `netbox_wireless_lan_group` ([#859](https://github.com/e-breuninger/terraform-provider-netbox/pull/859) by [@JonasKop](https://github.com/JonasKop))\n* resource/netbox_virtual_machine: Support auto-calculation of `disk_size_mb` attribute ([#854](https://github.com/e-breuninger/terraform-provider-netbox/pull/854) by [@keshy7](https://github.com/keshy7))\n* resource/netbox_ip_range: Add `custom_fields` attribute ([#842](https://github.com/e-breuninger/terraform-provider-netbox/pull/842) by [@jonas-sjodin-stegra](https://github.com/jonas-sjodin-stegra))\n* resource/netbox_available_ip_address: Add `custom_fields` attribute ([#841](https://github.com/e-breuninger/terraform-provider-netbox/pull/841) by [@jonas-sjodin-stegra](https://github.com/jonas-sjodin-stegra))\n* resource/netbox_interface: Add `bridge_interface_id` attribute ([#856](https://github.com/e-breuninger/terraform-provider-netbox/pull/856) by [@mraerino](https://github.com/mraerino))\n* data-source/netbox_ip_addresses: Add `custom_fields` attribute ([#848](https://github.com/e-breuninger/terraform-provider-netbox/pull/848) by [@jonas-sjodin-stegra](https://github.com/jonas-sjodin-stegra))\n* data-source/netbox_vlans: Add `id` attribute ([#662](https://github.com/e-breuninger/terraform-provider-netbox/pull/662) by [@rypti](https://github.com/rypti))\n* resource/netbox_cable: Add `usb` as option for `type` attribute ([#858](https://github.com/e-breuninger/terraform-provider-netbox/pull/858) by [@JonasKop](https://github.com/JonasKop))\n\nBUG FIXES\n\n* provider: use better error checking in many read functions ([#864](https://github.com/e-breuninger/terraform-provider-netbox/pull/864) by [@MrKeiKun](https://github.com/MrKeiKun))\n* resource/netbox_token: Handle `expires` field correctly ([#853](https://github.com/e-breuninger/terraform-provider-netbox/pull/853) by [@Oceaneyes123](https://github.com/Oceaneyes123))\n\n## 5.2.1 (March 12th, 2026)\n\nENHANCEMENTS\n\n* All plural data sources now use pagination ([#846](https://github.com/e-breuninger/terraform-provider-netbox/pull/846) by [@mcanevet](https://github.com/mcanevet))\n* Ignore unset custom fields ([#844](https://github.com/e-breuninger/terraform-provider-netbox/pull/844) by [@mcanevet](https://github.com/mcanevet))\n\n## 5.2.0 (March 11th, 2026)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_vlan_groups` ([#787](https://github.com/e-breuninger/terraform-provider-netbox/pull/787) by [@hp197](https://github.com/hp197))\n* data-source/netbox_vlan_group: Add `id` attribute ([#787](https://github.com/e-breuninger/terraform-provider-netbox/pull/787) by [@hp197](https://github.com/hp197))\n* data-source/netbox_ip_range: Add many missing filters ([#827](https://github.com/e-breuninger/terraform-provider-netbox/pull/827) by [@oliverwiegers](https://github.com/oliverwiegers))\n\nBUG FIXES\n\n* resource/netbox_available_ip_address: Force replacement when `prefix_id` or `ip_range_id` changes ([#837](https://github.com/e-breuninger/terraform-provider-netbox/pull/837) by [@bl0way](https://github.com/bl0way))\n\n## 5.1.0 (January 26th, 2026)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_device_render_config` ([#816](https://github.com/e-breuninger/terraform-provider-netbox/pull/816) by [@lgogolin](https://github.com/lgogolin))\n* **New Data Source:** `netbox_clusters` ([#817](https://github.com/e-breuninger/terraform-provider-netbox/pull/817) by [@sasler](https://github.com/sasler))\n* data-source/netbox_prefix: Add support for filtering netbox_prefix by custom fields ([#819](https://github.com/e-breuninger/terraform-provider-netbox/pull/819) by [@christopher-svensson-stegra](https://github.com/christopher-svensson-stegra))\n\nBUG FIXES\n\n* Fix an error where datasources with boolean custom fields returned 'expected type string, got unconvertible type bool' ([#814](https://github.com/e-breuninger/terraform-provider-netbox/pull/814) by [@mcanevet](https://github.com/mcanevet))\n\n## 5.0.1 Ho-Ho-Ho (December 25th, 2025) \n\nENHANCEMENTS\n\n* resource/netbox_circuit: Add `description` attribute ([#766](https://github.com/e-breuninger/terraform-provider-netbox/pull/766) by [@jakegroves](https://github.com/jakegroves))\n* resource/netbox_circuit_provider: Add `description` attribute ([#766](https://github.com/e-breuninger/terraform-provider-netbox/pull/766) by [@jakegroves](https://github.com/jakegroves))\n* resource/netbox_circuit_termination: Add `description` attribute ([#766](https://github.com/e-breuninger/terraform-provider-netbox/pull/766) by [@jakegroves](https://github.com/jakegroves))\n* resource/netbox_circuit_type: Add `description` attribute ([#766](https://github.com/e-breuninger/terraform-provider-netbox/pull/766) by [@jakegroves](https://github.com/jakegroves))\n* data-source/netbox_site: Add `physical_address` attribute to result ([#781](https://github.com/e-breuninger/terraform-provider-netbox/pull/781) by [@sytmd](https://github.com/sytmd))\n* data_source/netbox_ip_addresses: Add `description` attribute to results ([#784](https://github.com/e-breuninger/terraform-provider-netbox/pull/784) by [@christopher-svensson-stegra](https://github.com/christopher-svensson-stegra))\n* resource/netbox_event_rule: Allow `script` action type ([#799](https://github.com/e-breuninger/terraform-provider-netbox/pull/799) by [@jorgenspange](https://github.com/jorgenspange))\n* data-source/netbox_prefixes: Add `custom_fields` to results ([#779](https://github.com/e-breuninger/terraform-provider-netbox/pull/779) by [@lgogolin](https://github.com/lgogolin))\n* resource/netbox_webhook: Add `ca_file_path` attribute ([#797](https://github.com/e-breuninger/terraform-provider-netbox/pull/797) by [@jorgenspange](https://github.com/jorgenspange))\n* data-source/netbox_virtual_machines: Add `platform_name` to results ([#810](https://github.com/e-breuninger/terraform-provider-netbox/pull/810) by [@Slartibartfast1](https://github.com/Slartibartfast1))\n\nBUG FIXES\n\n* resource/netbox_user: Fix date_joined datetime out of range error ([#796](https://github.com/e-breuninger/terraform-provider-netbox/pull/796) by [@luispcoutinho](https://github.com/luispcoutinho))\n* resource/netbox_ip_address: Fix IP Address Assignment being removed despite being in ignore_changes ([#790](https://github.com/e-breuninger/terraform-provider-netbox/pull/790) by [@chuyang-wang-dev](https://github.com/chuyang-wang-dev))\n\n## 5.0.0 (September 12th, 2025)\n\nENHANCEMENTS\n\nprovider: Now supports NetBox 4.3.x and 4.4.0\n\n## 4.3.1 (September 12th, 2025)\n\nENHANCEMENTS\n\n* provider: Allow setting a CA file in the provider ([#765](https://github.com/e-breuninger/terraform-provider-netbox/pull/765) by [@bodgit](https://github.com/bodgit))\n\n## 4.3.0 (September 11th, 2025)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_rir` ([#759](https://github.com/e-breuninger/terraform-provider-netbox/pull/759) by [@MrKeiKun](https://github.com/MrKeiKun))\n* data-source/netbox_prefixes: Allow filtering by `description` ([#756](https://github.com/e-breuninger/terraform-provider-netbox/pull/756) by [@jonas-sjodin-h2gs](https://github.com/jonas-sjodin-h2gs))\n* resource/netbox_contact: Add `link` and `description` attributes ([#753](https://github.com/e-breuninger/terraform-provider-netbox/pull/753) by [@hikhvar](https://github.com/hikhvar))\n* resource/netbox_ip_range: Add `size` attribute ([#761](https://github.com/e-breuninger/terraform-provider-netbox/pull/761) by [@MrKeiKun](https://github.com/MrKeiKun))\n* data-source/netbox_device_interfaces: Add `type` attribute to results ([#764](https://github.com/e-breuninger/terraform-provider-netbox/pull/764) by [@xvzf](https://github.com/xvzf))\n\nBUG FIXES\n\n* resource/netbox_available_ip_address: Prevent provider crash when no IP is available ([#760](https://github.com/e-breuninger/terraform-provider-netbox/pull/760) by [@MrKeiKun](https://github.com/MrKeiKun))\n\n## 4.2.0 (August 20th, 2025)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_device_bay` ([#734](https://github.com/e-breuninger/terraform-provider-netbox/pull/734) by [@kyleprice](https://github.com/kyleprice))\n* **New Resource:** `netbox_device_bay_template` ([#734](https://github.com/e-breuninger/terraform-provider-netbox/pull/734) by [@kyleprice](https://github.com/kyleprice))\n* **New Data Source:** `netbox_ip_address` ([#743](https://github.com/e-breuninger/terraform-provider-netbox/pull/743) by [@c24holdingit](https://github.com/c24holdingit))\n* resource/netbox_device_type: Add `subdevice_role` field ([#734](https://github.com/e-breuninger/terraform-provider-netbox/pull/734) by [@kyleprice](https://github.com/kyleprice))\n* data-source/netbox_device_type: Add `subdevice_role` field ([#734](https://github.com/e-breuninger/terraform-provider-netbox/pull/734) by [@kyleprice](https://github.com/kyleprice))\n* resource/netbox_token: Add `expires` field ([#742](https://github.com/e-breuninger/terraform-provider-netbox/pull/742) by [@thomas-VIGINUM](https://github.com/thomas-VIGINUM))\n\n## 4.1.0 (July 2nd, 2025)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_virtual_disk` ([#731](https://github.com/e-breuninger/terraform-provider-netbox/pull/731) by [@lgogolin](https://github.com/lgogolin))\n* resource/netbox_available_prefix: Add `custom_fields` attribute ([#679](https://github.com/e-breuninger/terraform-provider-netbox/pull/679) by [@rs-hock](https://github.com/rs-hock))\n* data-source/netbox_devices: Add `oob_ip` attribute to output([#705](https://github.com/e-breuninger/terraform-provider-netbox/pull/705) by [@sempervictus](https://github.com/sempervictus))\n\nBUG FIXES\n\n* provider: Now properly detects netbox-docker versions\n\n## 4.0.0 (June 12th, 2025)\n\n**BREAKING CHANGES**\n\nNetBox 4.2 came with some breaking changes and these are reflected in the provider.\n\n* resource/netbox_device_interface: Make `mac_address` attribute read-only\n* resource/netbox_device_interface: Add read-only `mac_addresses` attribute\n\nENHANCEMENTS\n\nprovider: Now supports NetBox 4.2.x\n* **New Resource:** `netbox_mac_address`\n* resource/netbox_cluster: Add `location_id`, `site_group_id`, `region_id`, `scope_id` and `scope_type` attributes\n* resource/netbox_prefix: Add `location_id`, `site_group_id` and `region_id` attributes\n* resource/netbox_device_interface: Allow `q-in-q` value in `mode` attribute\n* resource/netbox_circuit_termination: Add `location_id`, `site_group_id`, `region_id`, `site_id` and `provider_network_id` attributes\n\nBUG FIXES\n\n* resource/netbox_location: Mark `site_id` as required\n\n## 3.11.1 (June 12th, 2025)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_device_power_ports` ([#721](https://github.com/e-breuninger/terraform-provider-netbox/pull/721) by [@mraerino](https://github.com/mraerino))\n* **New Resource:** `netbox_available_vlan` ([#717](https://github.com/e-breuninger/terraform-provider-netbox/pull/717) by [@MacherelR](https://github.com/MacherelR))\n\n## 3.11.0 (May 27th, 2025)\n\n* provider: Add `default_tags` attribute ([#711](https://github.com/e-breuninger/terraform-provider-netbox/pull/711) by [@mraerino](https://github.com/mraerino))\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_ip_ranges` ([#719](https://github.com/e-breuninger/terraform-provider-netbox/pull/719) by [@waza-ari](https://github.com/waza-ari))\n* resource/netbox_device: Allow `decommissioning` value in `status` attribute ([#767](https://github.com/e-breuninger/terraform-provider-netbox/pull/767) by [@sboschman](https://github.com/sboschman))\n* resource/netbox_site: Add `comments` attribute ([#710](https://github.com/e-breuninger/terraform-provider-netbox/pull/710) by [@mraerino](https://github.com/mraerino))\n* resource/netbox_user: Add `email`, `first_name` and `last_name` attributes ([#693](https://github.com/e-breuninger/terraform-provider-netbox/pull/693) by [@mraerino](https://github.com/mraerino))\n* data-source/netbox_device_interfaces: Add `limit` attribute ([#695](https://github.com/e-breuninger/terraform-provider-netbox/pull/695) by [@sempervictus](https://github.com/sempervictus))\n* resource/netbox_group: Add `description` attribute ([#694](https://github.com/e-breuninger/terraform-provider-netbox/pull/694) by [@mraerino](https://github.com/mraerino))\n* resource/netbox_location: Add `facility` attribute ([#718](https://github.com/e-breuninger/terraform-provider-netbox/pull/718) by [@mraerino](https://github.com/mraerino))\n* data-source/netbox_locations: Add `facility` attribute ([#718](https://github.com/e-breuninger/terraform-provider-netbox/pull/718) by [@mraerino](https://github.com/mraerino))\n\n## 3.10.0 (January 9th, 2025)\n\n**BREAKING CHANGES**\n\nNetBox 4.1 came with some breaking changes and these are reflected in the provider.\n\n* resource/netbox_event_rule: Replace `trigger_on_X` attributes with `event_types` list attribute\n* resource/netbox_racks: Remove `type` attribute\n* resource/netbox_virtual_disk: Change `size_gb` attribute to `size_mb`\n* resource/netbox_virtual_machine: Change `disk_size_gb` attribute to `disk_size_mb`\n* resource/netbox_vlan_group: Remove `min_vid` and `max_vid` attributes in favor of `vid_ranges` attribute\n\nENHANCEMENTS\n\nprovider: Now supports NetBox 4.1.x\n* **New Resource:** `netbox_rack_type`\n* resource/netbox_racks: Add `form_factor` attribute\n\n## 3.9.3 (January 9th, 2025)\n\nENHANCEMENTS\n\n* resource/netbox_custom_field: Add `default` attribute ([#647](https://github.com/e-breuninger/terraform-provider-netbox/pull/647) by [@jenxie](https://github.com/jenxie))\n* data-source/netbox_vlans: Allow filtering by `site_id` ([#654](https://github.com/e-breuninger/terraform-provider-netbox/pull/654) by [@i-am-smolli](https://github.com/i-am-smolli))\n* data-source/netbox_vlan_group: Make `name` and `slug` definitions optional when `scope_type` is defined ([#657](https://github.com/e-breuninger/terraform-provider-netbox/pull/657) by [@TGM](https://github.com/TGM))\n* resource/netbox_asn: Add `description` and `comments` attributes ([#664](https://github.com/e-breuninger/terraform-provider-netbox/pull/664) by [@ymylei](https://github.com/ymylei))\n* data-source/netbox_prefix: Allow searching by `tenant_id` and `status` ([#666](https://github.com/e-breuninger/terraform-provider-netbox/pull/666) by [@xabinapal](https://github.com/xabinapal))\n* data-source/netbox_prefixes: Allow searching by `tenant_id` ([#666](https://github.com/e-breuninger/terraform-provider-netbox/pull/666) by [@xabinapal](https://github.com/xabinapal))\n\n## 3.9.2 (October 10th, 2024)\n\nENHANCEMENTS\n\n* provider: Include 4.0.11 in supported versions\n* resource/netbox_ip_address: Add `custom_fields` attribute ([#638](https://github.com/e-breuninger/terraform-provider-netbox/pull/638) by [@greatman](https://github.com/greatman))\n* resource/netbox_service: Add `device_id`, `description` and `tags` attributes ([#637](https://github.com/e-breuninger/terraform-provider-netbox/pull/637) by [@STANIAC](https://github.com/STANIAC))\n* data-source/netbox_vrf: Fix a bug where `tenant_id` was not used ([#643](https://github.com/e-breuninger/terraform-provider-netbox/pull/643) by [@c3JpbmkK](https://github.com/c3JpbmkK))\n\n## 3.9.1 (September 2nd, 2024)\n\nENHANCEMENTS\n\nprovider: Include 4.0.9 and 4.0.10 in supported versions\n\n## 3.9.0 (August 10th, 2024)\n\nENHANCEMENTS\n\nprovider: Now is tested against (= supports) the NetBox 4.0.x range\n\n## 3.8.9 (July 31st, 2024)\n\nENHANCEMENTS\n\n* data-source/netbox_virtual_machines: Add `status` attribute ([#612](https://github.com/e-breuninger/terraform-provider-netbox/pull/612) by [@twink0r](https://github.com/twink0r))\n* data-source/netbox_vlans: Add `tag_ids` attribute ([#621](https://github.com/e-breuninger/terraform-provider-netbox/pull/621) by [@Piethan](https://github.com/Piethan))\n* data-source/netbox_vlans: Add `status` attribute ([#622](https://github.com/e-breuninger/terraform-provider-netbox/pull/622) by [@Piethan](https://github.com/Piethan))\n* data-source/netbox_devices: Add `device_type_id` attribute ([#624](https://github.com/e-breuninger/terraform-provider-netbox/pull/624) by [@Piethan](https://github.com/Piethan))\n\n## 3.8.8 (July 22th, 2024)\n\nENHANCEMENTS\n\n* data-source/netbox_prefixes: Add `contains` and `site_id` attributes ([#617](https://github.com/e-breuninger/terraform-provider-netbox/pull/617) by [@tagur87](https://github.com/tagur87))\n\nBUG FIXES\n\n* resource/netbox_vpn_tunnel_termination: Fix a interface conversion panic when updating tunnel terminations ([#616](https://github.com/e-breuninger/terraform-provider-netbox/pull/616) by [@mraerino](https://github.com/mraerino))\n\n## 3.8.7 (June 28th, 2024)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_interface_template` ([#588](https://github.com/e-breuninger/terraform-provider-netbox/pull/588) by [@thibaultbustarret-ovhcloud](https://github.com/thibaultbustarret-ovhcloud))\n* **New Resource:** `netbox_config_context` ([#590](https://github.com/e-breuninger/terraform-provider-netbox/pull/590) by [@diogenxs](https://github.com/diogenxs))\n* **New Data Source:** `netbox_config_context` ([#590](https://github.com/e-breuninger/terraform-provider-netbox/pull/590) by [@diogenxs](https://github.com/diogenxs))\n* data-source/netbox_devices: Add `config_context` and `local_context_data` attributes ([#590](https://github.com/e-breuninger/terraform-provider-netbox/pull/590) by [@diogenxs](https://github.com/diogenxs))\n* resource/netbox_device_interface: Add `label` attribute ([#605](https://github.com/e-breuninger/terraform-provider-netbox/pull/605) by [@thibaultbustarret-ovhcloud](https://github.com/thibaultbustarret-ovhcloud))\n* **New Resource:** `netbox_config_template` ([#604](https://github.com/e-breuninger/terraform-provider-netbox/pull/604) by [@thibaultbustarret-ovhcloud](https://github.com/thibaultbustarret-ovhcloud))\n* resource/netbox_device: Add `config_template_id` attribute ([#604](https://github.com/e-breuninger/terraform-provider-netbox/pull/604) by [@thibaultbustarret-ovhcloud](https://github.com/thibaultbustarret-ovhcloud))\n* data-source/netbox_prefix: Add `role_id` and `custom_fields` attributes ([#607](https://github.com/e-breuninger/terraform-provider-netbox/pull/607) by [@ad8lmondy](https://github.com/ad8lmondy))\n* resource/netbox_platform: Add `manufacturer_id` attribute ([#608](https://github.com/e-breuninger/terraform-provider-netbox/pull/608) by [@ad8lmondy](https://github.com/ad8lmondy))\n* data-source/netbox_platform: Add `manufacturer_id` attribute ([#608](https://github.com/e-breuninger/terraform-provider-netbox/pull/608) by [@ad8lmondy](https://github.com/ad8lmondy))\n\n## 3.8.6 (May 17th, 2024)\n\nENHANCEMENTS\n\n* resource/netbox_rir: Add `is_private` attribute ([#594](https://github.com/e-breuninger/terraform-provider-netbox/pull/594) by [@thibaultbustarret-ovhcloud](https://github.com/thibaultbustarret-ovhcloud))\n* resource/netbox_vrf: Add `rd` and `enforce_unique` attributes ([#585](https://github.com/e-breuninger/terraform-provider-netbox/pull/585) by [@thibaultbustarret-ovhcloud](https://github.com/thibaultbustarret-ovhcloud))\n* **New Resource:** `netbox_group` ([#584](https://github.com/e-breuninger/terraform-provider-netbox/pull/584) by [@thibaultbustarret-ovhcloud](https://github.com/thibaultbustarret-ovhcloud))\n* resource/netbox_user: Add `group_ids` attribute ([#584](https://github.com/e-breuninger/terraform-provider-netbox/pull/584) by [@thibaultbustarret-ovhcloud](https://github.com/thibaultbustarret-ovhcloud))\n\n## 3.8.5 (March 18th, 2024)\n\nBUG FIXES\n\n* All resources with `slug` attributes now properly allow for up to 100 characters in that attribute\n\n## 3.8.4 (March 11th, 2024)\n\nENHANCEMENTS\n\n* data-source/netbox_interfaces: Add `limit` attribute\n\n## 3.8.3 (March 8th, 2024)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_vpn_tunnel_termination`\n\n## 3.8.2 (March 4th, 2024)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_virtual_disk` ([#558](https://github.com/e-breuninger/terraform-provider-netbox/pull/558) by [@Ikke](https://github.com/Ikke))\n* resource/netbox_prefix: Add `custom_fields` attribute ([#553](https://github.com/e-breuninger/terraform-provider-netbox/pull/553) by [@nothinux](https://github.com/nothinux))\n\n## 3.8.1 (February 16th, 2024)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_vpn_tunnel_group`\n* **New Resource:** `netbox_vpn_tunnel`\n* data-source/netbox_virtual_machines: Add `platform_slug` attribute\n* data-source/netbox_locations: Add `parent_id` attribute ([#548](https://github.com/e-breuninger/terraform-provider-netbox/pull/548) by [@GennadySpb](https://github.com/GennadySpb))\n* data-source/netbox_location: Add `parent_id` attribute ([#548](https://github.com/e-breuninger/terraform-provider-netbox/pull/548) by [@GennadySpb](https://github.com/GennadySpb))\n* resource/netbox_location: Add `parent_id` attribute ([#548](https://github.com/e-breuninger/terraform-provider-netbox/pull/548) by [@GennadySpb](https://github.com/GennadySpb))\n* resource/device_type: Add `is_full_depth` attribute\n\n## 3.8.0 (January 30th, 2024)\n\n**BREAKING CHANGES**\nDue to a change in NetBox 3.7's behavior regarding Webhooks and the corresponding changes in the API,\nthe `netbox_webhook` resource might cause problems with NetBox versions older than 3.7.0.\nFor all other resources and data sources, the provider should still perform fine with older NetBox versions.\n\n* resource/netbox_webhook: Removed `enabled`, `trigger_on_create`, `trigger_on_update`, `trigger_on_delete`, `content_types` and `conditions`\n\nENHANCEMENTS\n\n* provider: Now officially supports NetBox 3.7\n* **New Resource:** `netbox_event_rule`\n\n## 3.7.7 (January 30th, 2024)\n\nBUG FIXES\n\n* resource/netbox_device: Fix Virtual Chassis Master Update Function for Tag Input ([#532](https://github.com/e-breuninger/terraform-provider-netbox/pull/532) by [@adelekanley](https://github.com/adelekanley))\n\n## 3.7.6 (January 2nd, 2024)\n\nENHANCEMENTS\n\n* resource/netbox_webhook: Add `additional_headers` and `conditions` attributes ([#505](https://github.com/e-breuninger/terraform-provider-netbox/pull/505) by [@Ikke](https://github.com/Ikke))\n* data-source/netbox_vrfs: Allow filtering by `tag` ([#513](https://github.com/e-breuninger/terraform-provider-netbox/pull/513) by [@sjurtf](https://github.com/sjurtf))\n* data-source/netbox_virtual_machines: Allow filtering by `tenant_id` ([#511](https://github.com/e-breuninger/terraform-provider-netbox/pull/511) by [@sjurtf](https://github.com/sjurtf))\n* data-source/netbox_ip_addresses: Allow filtering by `tag` ([#510](https://github.com/e-breuninger/terraform-provider-netbox/pull/510) by [@sjurtf](https://github.com/sjurtf))\n* data-source/netbox_cluster: Allow filtering by `cluster_group_id` ([#528](https://github.com/e-breuninger/terraform-provider-netbox/pull/528) by [@Ikke](https://github.com/Ikke))\n\nBUG FIXES\n\n* resources/netbox_webhook: Fix a bug where JSON encoding would break drift detection ([#505](https://github.com/e-breuninger/terraform-provider-netbox/pull/505) by [@Ikke](https://github.com/Ikke))\n* data-source/netbox_site: Mark optionally searchable attributes as `computed` as well ([#520](https://github.com/e-breuninger/terraform-provider-netbox/pull/520) by [@tagur87](https://github.com/tagur87))\n\n## 3.7.5 (November 27th, 2023)\n\n* **New Data Source:** `netbox_locations` ([#503](https://github.com/e-breuninger/terraform-provider-netbox/pull/503) by [@Ikke](https://github.com/Ikke))\n\n## 3.7.4 (November 22nd, 2023)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_virtual_chassis` ([#497](https://github.com/e-breuninger/terraform-provider-netbox/pull/497) by [@Ikke](https://github.com/Ikke))\n* resource/netbox_device: Add `virtual_chassis_id`, `virtual_chassis_master`, `virtual_chassis_position` and `virtual_chassis_priority` attributes ([#500](https://github.com/e-breuninger/terraform-provider-netbox/pull/500) by [@Ikke](https://github.com/Ikke))\n\n## 3.7.3 (November 3rd, 2023)\n\nENHANCEMENTS\n\n* resource/netbox_site: Allow unsetting the `latitude` and `longitude` attributes ([#480](https://github.com/e-breuninger/terraform-provider-netbox/pull/480) by [@haipersuccor02](https://github.com/haipersuccor02))\n* **New Data Source:** `netbox_tags` ([#484](https://github.com/e-breuninger/terraform-provider-netbox/pull/484) by [@zeddD1abl0](https://github.com/zeddD1abl0))\n* data-source/netbox_ip_addresses: Allow filtering by `parent_prefix` ([#485](https://github.com/e-breuninger/terraform-provider-netbox/pull/485) by [@sjurtf](https://github.com/sjurtf))\n* data-source/netbox_devices: Allow filtering by `tags` and `status` ([#491](https://github.com/e-breuninger/terraform-provider-netbox/pull/491) by [@Kenterfie](https://github.com/Kenterfie))\n* **New Data Source:** `netbox_available_prefixes` ([#489](https://github.com/e-breuninger/terraform-provider-netbox/pull/489) by [@theochita](https://github.com/theochita))\n* resource/netbox_device: Add `local_context_data` attribute ([#493](https://github.com/e-breuninger/terraform-provider-netbox/pull/493) by [@RickyRajinder](https://github.com/RickyRajinder))\n\n## 3.7.2 (October 10th, 2023)\n\nENHANCEMENTS\n\n* data-source/netbox_location: Allow searching by `site_id` ([#482](https://github.com/e-breuninger/terraform-provider-netbox/pull/482) by [@w87x](https://github.com/w87x))\n* data-source/netbox_ip_addresses: Allow searching by `role`, `status`, `vrf` and `tenant` ([#479](https://github.com/e-breuninger/terraform-provider-netbox/pull/479) by [@sjurtf](https://github.com/sjurtf))\n* data-source/netbox_site: Allow Searching by `facility` ([#483](https://github.com/e-breuninger/terraform-provider-netbox/pull/483) by [@ikke](https://github.com/ikke))\n\n## 3.7.1 (September 25th, 2023)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_device_interfaces` ([#476](https://github.com/e-breuninger/terraform-provider-netbox/pull/476) by [@w87x](https://github.com/w87x))\n* resource/netbox_token: Add `description` attribute ([#473](https://github.com/e-breuninger/terraform-provider-netbox/pull/473) by [@twink0r](https://github.com/twink0r))\n* data-source/netbox_virtual_machines: Include `device_id` and `device_name` attributes in result ([#477](https://github.com/e-breuninger/terraform-provider-netbox/pull/477) by [@zeddD1abl0](https://github.com/zeddD1abl0))\n\n## 3.7.0 (September 14th, 2023)\n\n**BREAKING CHANGES**\n\n* resource/netbox_custom_field: Replace `choices` attribute with `choice_set_id` attribute\n\nENHANCEMENTS\n\n* provider: Now officially supports NetBox 3.6\n* **New Resource:** `netbox_custom_field_choice_set`\n\n## 3.6.2 (September 14th, 2023)\n\nFEATURES\n\n* **New Data Source:** `netbox_location` ([#467](https://github.com/e-breuninger/terraform-provider-netbox/pull/467) by [@w87x](https://github.com/w87x))\n* data-source/netbox_virtual_machines: Allow searching by tag ([#466](https://github.com/e-breuninger/terraform-provider-netbox/pull/466) by [@twink0r](https://github.com/twink0r))\n* resource/netbox_device: Add `asset_tag` attribute ([#470](https://github.com/e-breuninger/terraform-provider-netbox/pull/470) by [@bebehei](https://github.com/bebehei))\n* resource/netbox_device_interface: Add `speed`, `lag_device_interface_id` and `parent_device_interface_id` attributes ([#469](https://github.com/e-breuninger/terraform-provider-netbox/pull/469) by [@bebehei](https://github.com/bebehei))\n\nBUG FIXES\n\n* resource/netbox_custom_field: Allow correct value `json` instead of `JSON` ([#459](https://github.com/e-breuninger/terraform-provider-netbox/pull/459) by [@menselman](https://github.com/menselman))\n\n## 3.6.1 (August 31th, 2023)\n\nFEATURES\n\n* **New Resource:** `netbox_webhook` ([#438](https://github.com/e-breuninger/terraform-provider-netbox/pull/438) by [@haipersuccor02](https://github.com/haipersuccor02))\n\n## 3.6.0 (August 18th, 2023)\n\n**BREAKING CHANGES**\nDue to a change in NetBox 3.5's behavior regarding ASN and the corresponding required changes in the go library that is used in this provider,\nthe `netbox_asn` resource and the `netbox_asns` data source are no longer supported in versions older than 3.5.\nFor all other resources and data sources, the provider should still perform fine with older NetBox versions.\n\nENHANCEMENTS\n\n* provider: Now officially supports NetBox 3.5\n\n## 3.5.5 (August 18th, 2023)\n\nENHANCEMENTS\n\n* data-source/netbox_cluster: Allow searching by `id` field and include `custom_fields` attribute in output ([#457](https://github.com/e-breuninger/terraform-provider-netbox/pull/457) by [@fred-clement-91](https://github.com/fred-clement-91))\n\nBUG FIXES\n\n* resource/netbox_device_interface: Changing `mac_address` no longer needlessly forces a recreate of the resource ([#454](https://github.com/e-breuninger/terraform-provider-netbox/pull/454) by [@hamzazaman](https://github.com/hamzazaman))\n\n## 3.5.4 (August 7th, 2023)\n\nFEATURES\n\n* **New Resource:** `netbox_cable` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_device_console_port` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_device_console_server_port` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_device_power_port` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_device_power_outlet` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_device_front_port` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_device_rear_port` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_device_module_bay` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_module` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_module_type` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_power_feed` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_power_panel` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_inventory_item_role` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_inventory_item` ([#450](https://github.com/e-breuninger/terraform-provider-netbox/pull/450) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n\n## 3.5.3 (August 4th, 2023)\n\nENHANCEMENTS\n\n* resource/netbox_service: Add `custom_fields` attribute ([#448](https://github.com/e-breuninger/terraform-provider-netbox/pull/448) by [@sebastianreloaded](https://github.com/sebastianreloaded))\n* data-source/netbox_site: Allow searching by `id` field\n\nBUG FIXES\n\n* resource/netbox_interface: Allow setting `enabled` to `false`\n* resource/netbox_device_interface: Allow setting `enabled` to `false`\n\n## 3.5.2 (August 3rd, 2023)\n\nFEATURES\n\n* **New Data Source:** `netbox_vrfs` ([#441](https://github.com/e-breuninger/terraform-provider-netbox/pull/441) by [@robvand](https://github.com/robvand))\n\nENHANCEMENTS\n\n* Added `description` attribute to\n  - data-source/netbox_cluster\n  - data-source/netbox_devices\n  - data-source/netbox_virtual_machines\n  - resource/netbox_cluster\n  - resource/netbox_device\n  - resource/virtual_machine ([#401](https://github.com/e-breuninger/terraform-provider-netbox/pull/401) by [@tagur87](https://github.com/tagur87))\n* data-source/netbox_devices: Return `tags` attribute\n* resource/netbox_interface: Ignore drift when providing lowercase MAC addresses ([#446](https://github.com/e-breuninger/terraform-provider-netbox/pull/446) by [@bebehei](https://github.com/bebehei))\n* resource/netbox_device_interface: Ignore drift when providing lowercase MAC addresses ([#446](https://github.com/e-breuninger/terraform-provider-netbox/pull/446) by [@bebehei](https://github.com/bebehei))\n\n## 3.5.1 (July 24th, 2023)\n\nBUG FIXES\n\n* resource/netbox_ip_address: Use correct attribute when using the `device_interface_id` attribute ([#437](https://github.com/e-breuninger/terraform-provider-netbox/pull/437) by [@switchcorp](https://github.com/switchcorp))\n* resource/netbox_primary_ip: Fix a bug where setting a primary IP unsets the `local_context_data` attribute ([#435](https://github.com/e-breuninger/terraform-provider-netbox/pull/435) by [@tagur87](https://github.com/tagur87))\n\n## 3.5.0 (July 20th, 2023)\n\n**BREAKING CHANGES**\nHistorically, this provider primarily handled virtual machines, so when linking a `netbox_ip_address` resource to an interface, the interface was initially assumed to always be a virtual machine interface. In [v3.1.0](https://github.com/e-breuninger/terraform-provider-netbox/commit/76f11292a162d88eb1616d9a5b7d70d986b2db3f), support was added for device interfaces by setting the newly introduced `object_type` attribute, once again defaulting to virtual machine interfaces. The valid values for `object_type` directly reflect the API values of NetBox, which are very unintuitive.\n\nIn this version, we make the type of connection between IP addresses and interfaces explicit: We introduce two new attributes: `virtual_machine_interface_id` and `device_interface_id` to the `netbox_ip_address` resource. These fields are easier to use and convey their meaning directly to the user. The `object_type` and `interface_id` method is still supported, but `object_type` no longer has a default value and is now mandatory when `interface_id` is used.\n\n**Migration guide**\n\nIn your existing codebase:\n\n* replace `interface_id` with `virtual_machine_interface_id` if `object_type` is currently unset or set to `virtualization.vminterface`\n* replace `interface_id` with `device_interface_id` if `object_type` is currently set to `dcim.interface`\n\nENHANCEMENTS\n\n* resource/netbox_ip_address: Add `virtual_machine_interface_id` and `device_interface_id` attributes \n* resource/netbox_ip_address: Add `slaac` to the list of valid statuses\n* resource/netbox_ip_address: Add `nat_inside_address_id` and `nat_outside_addresses` attributes\n\nBUG FIXES\n\n* resource/netbox_permission: Fix perpetual drift when `constraints` is nil ([#432](https://github.com/e-breuninger/terraform-provider-netbox/pull/432) by [@tagur87](https://github.com/tagur87))\n\n## 3.4.1 (July 19th, 2023)\n\nENHANCEMENTS\n\n* resource/netbox_cluster: Add `comments` attribute ([#429](https://github.com/e-breuninger/terraform-provider-netbox/pull/429) by [@edwin-bruurs](https://github.com/edwin-bruurs))\n* data-source/netbox_prefix: Add `family` attribute ([#431](https://github.com/e-breuninger/terraform-provider-netbox/pull/431) by [@tagur87](https://github.com/tagur87))\n\nBUG FIXES\n\n* resource/netbox_virtual_machine: Fix `local_context_data` attribute ([#430](https://github.com/e-breuninger/terraform-provider-netbox/pull/430) by [@zeddD1abl0](https://github.com/zeddD1abl0))\n\n## 3.4.0 (July 10th, 2023)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_device_primary_ip` ([#424](https://github.com/e-breuninger/terraform-provider-netbox/pull/424) by [@Ikke](https://github.com/Ikke))\n* resource/netbox_virtual_machine: Add `local_context_data` attribute ([#421](https://github.com/e-breuninger/terraform-provider-netbox/pull/421) by [@zeddD1abl0](https://github.com/zeddD1abl0))\n\nBUG FIXES\n\n* resource/netbox_primary_ip: Fix a bug where setting the primary ip of a VM unsets the device id\n\n## 3.3.3 (June 28th, 2023)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_vlans` ([#420](https://github.com/e-breuninger/terraform-provider-netbox/pull/420) by [@danischm](https://github.com/danischm))\n* resource/netbox_contact_assignment: Add `priority` attribute ([#418](https://github.com/e-breuninger/terraform-provider-netbox/pull/418) by [@Ikke](https://github.com/Ikke))\n\n## 3.3.2 (June 12th, 2023)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_contact_role` ([#414](https://github.com/e-breuninger/terraform-provider-netbox/pull/414) by [@Ikke](https://github.com/Ikke))\n\n## 3.3.1 (May 31th, 2023)\n\nENHANCEMENTS\n\n* data-source/netbox_prefixes: Allow filtering by `site_id` ([#397](https://github.com/e-breuninger/terraform-provider-netbox/pull/397) by [@tagur87](https://github.com/tagur87))\n* data-source/netbox_ip_addresses: Add `tags` attributes to output ([#406](https://github.com/e-breuninger/terraform-provider-netbox/pull/406) by [@pier-nl](https://github.com/pier-nl))\n* Improved error handling for tags ([#400](https://github.com/e-breuninger/terraform-provider-netbox/pull/400) by [@tagur87](https://github.com/tagur87))\n\n## 3.3.0 (May 7th, 2023)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_permission` ([#390](https://github.com/e-breuninger/terraform-provider-netbox/pull/390) by [@tagur87](https://github.com/tagur87))\n* **New Resource:** `netbox_contact_group` ([#366](https://github.com/e-breuninger/terraform-provider-netbox/pull/366) by [@leasley199](https://github.com/leasley199))\n* **New Data Source:** `netbox_contact_group` ([#366](https://github.com/e-breuninger/terraform-provider-netbox/pull/366) by [@leasley199](https://github.com/leasley199))\n* **New Data Source:** `netbox_contact` ([#366](https://github.com/e-breuninger/terraform-provider-netbox/pull/366) by [@leasley199](https://github.com/leasley199))\n* data-source/netbox_cluster: Allow searching by `site_id`\n\nBUG FIXES\n\n* resource/netbox_prefix: Allow unsetting `description` attribute ([#382](https://github.com/e-breuninger/terraform-provider-netbox/pull/382) by [@DevOpsFu](https://github.com/DevOpsFu))\n\n## 3.2.1 (April 27th, 2023)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_vlan_group` ([#377](https://github.com/e-breuninger/terraform-provider-netbox/pull/377) by [@zeddD1abl0](https://github.com/zeddD1abl0))\n* **New Data Source:** `netbox_vlan_group` ([#377](https://github.com/e-breuninger/terraform-provider-netbox/pull/377) by [@zeddD1abl0](https://github.com/zeddD1abl0))\n* resource/netbox_vlan: Add `group_id` attribute ([#377](https://github.com/e-breuninger/terraform-provider-netbox/pull/377) by [@zeddD1abl0](https://github.com/zeddD1abl0))\n\nBUG FIXES\n\n* data-source/netbox_prefixes: Fix error when filtering by `vlan_vid` ([#381](https://github.com/e-breuninger/terraform-provider-netbox/pull/381) by [@zeddD1abl0](https://github.com/zeddD1abl0))\n\n## 3.2.0 (March 26th, 2023)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_route_target` ([#344](https://github.com/e-breuninger/terraform-provider-netbox/pull/344) by [@imdhruva](https://github.com/imdhruva))\n* **New Resource:** `netbox_rack` ([#358](https://github.com/e-breuninger/terraform-provider-netbox/pull/358) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_rack_reservation` ([#358](https://github.com/e-breuninger/terraform-provider-netbox/pull/358) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Resource:** `netbox_rack_role` ([#358](https://github.com/e-breuninger/terraform-provider-netbox/pull/358) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Data Source:** `netbox_ipam_role` ([#344](https://github.com/e-breuninger/terraform-provider-netbox/pull/344) by [@imdhruva](https://github.com/imdhruva))\n* **New Data Source:** `netbox_route_target` ([#344](https://github.com/e-breuninger/terraform-provider-netbox/pull/344) by [@imdhruva](https://github.com/imdhruva))\n* **New Data Source:** `netbox_racks` ([#358](https://github.com/e-breuninger/terraform-provider-netbox/pull/358) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* **New Data Source:** `netbox_rack_role` ([#358](https://github.com/e-breuninger/terraform-provider-netbox/pull/358) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* resource/netbox_device: Add `rack_face`,  `rack_id` and `rack_position` attributes ([#358](https://github.com/e-breuninger/terraform-provider-netbox/pull/358) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* data-source/netbox_device: Add `rack_face`,  `rack_id` and `rack_position` attributes ([#358](https://github.com/e-breuninger/terraform-provider-netbox/pull/358) by [@joeyberkovitz](https://github.com/joeyberkovitz))\n* data-source/netbox_prefixes: Add support for filtering by `status` and `tag` ([#367](https://github.com/e-breuninger/terraform-provider-netbox/pull/367) by [@kyle-burnett](https://github.com/kyle-burnett))\n* resource/netbox_location: Add `description` attribute\n* resource/netbox_rir: Add `description` attribute\n* resource/netbox_vrf: Add `description` attribute\n* data-source/netbox_prefixes: Include `description` attribute in search results\n* data-source/netbox_ip_addresses: Add `limit` attribute (default 1000)\n\n## 3.1.0 (February 19th, 2023)\n\nCHANGES\n\n* provider: `slug` fields are now generated to match the netbox GUI behavior\n\nENHANCEMENTS\n\n* resource/netbox_interface: Updating `mac_address` no longer forces resource recreation ([#336](https://github.com/e-breuninger/terraform-provider-netbox/pull/336) by [@johann8384](https://github.com/johann8384))\n* resource/netbox_site: Add `physical_address` and `shipping_address` ([#337](https://github.com/e-breuninger/terraform-provider-netbox/pull/337) by [@Ikke](https://github.com/Ikke))\n* resource/netbox_ip_address: IP addresses can now be assigned to devices via the `object_type` field ([#341](https://github.com/e-breuninger/terraform-provider-netbox/pull/341) by [@arjenvri](https://github.com/arjenvri))\n\n## 3.0.13 (January 24th, 2023)\n\nENHANCEMENTS\n\n* data-source/netbox_prefix: Add `site_id` attribute ([#320](https://github.com/e-breuninger/terraform-provider-netbox/pull/320) by [@TGM](https://github.com/TGM))\n\n## 3.0.12 (January 3rd, 2023)\n\nENHANCEMENTS\n\n* resource/netbox_token: Add `write_enabled` attribute ([#309](https://github.com/e-breuninger/terraform-provider-netbox/pull/309) by [@keshy7](https://github.com/keshy7))\n* data-source/netbox_interfaces: The resulting interfaces now have their interface ID set\n\nBUG FIXES\n\n* resource/site: Allow unsetting `description` attribute ([#314](https://github.com/e-breuninger/terraform-provider-netbox/pull/314) by [@keshy7](https://github.com/keshy7))\n* resource/site: Set max length of the `slug` attribute to 100 ([#317](https://github.com/e-breuninger/terraform-provider-netbox/pull/317) by [@keshy7](https://github.com/keshy7))\n\n## 3.0.11 (December 13th, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_available_ip_address: Add `role` attribute\n\nBUG FIXES\n\n* resource/netbox_location: Fix updates of the `site_id` attribute ([#307](https://github.com/e-breuninger/terraform-provider-netbox/pull/307) by [@nneul](https://github.com/nneul))\n\n## 3.0.10 (November 24th, 2022)\n\nENHANCEMENTS\n\n* provider: Add `strip_trailing_slashes_from_url` attribute\n\nBUG FIXES\n\n* data-source/netbox_region: Use correct field for slug attribute ([#302](https://github.com/e-breuninger/terraform-provider-netbox/pull/302) by [@paulexyz](https://github.com/paulexyz))\n\n## 3.0.9 (November 17th, 2022)\n\nENHANCEMENTS\n\n* data-source/netbox_vlan: Allow querying by `group_id`, `role` and `tenant` ([#287](https://github.com/e-breuninger/terraform-provider-netbox/pull/287) by [@tstarck](https://github.com/tstarck))\n* data-source/netbox_prefix: Allow querying by `description` ([#298](https://github.com/e-breuninger/terraform-provider-netbox/pull/298) by [@luispcoutinho](https://github.com/luispcoutinho))\n\n## 3.0.8 (November 9th, 2022)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_device_interface` ([#286](https://github.com/e-breuninger/terraform-provider-netbox/pull/286) by [@arjenvri](https://github.com/arjenvri))\n* **New Data Source:** `netbox_asn` ([#285](https://github.com/e-breuninger/terraform-provider-netbox/pull/285) by [@kyle-burnett](https://github.com/kyle-burnett))\n* **New Data Source:** `netbox_asns` ([#292](https://github.com/e-breuninger/terraform-provider-netbox/pull/292) by [@kyle-burnett](https://github.com/kyle-burnett))\n* data-source/netbox_prefix: Add `tags` and tag filter attributes ([#284](https://github.com/e-breuninger/terraform-provider-netbox/pull/284) by [@kyle-burnett](https://github.com/kyle-burnett))\n\nBUG FIXES\n\n* data-source/netbox_prefixes: Fix kernel panic when finding prefixes without vlan or vrf\n\n## 3.0.7 (November 3rd, 2022)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_contact_role` ([#279](https://github.com/e-breuninger/terraform-provider-netbox/pull/279) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_contact_assignment` ([#279](https://github.com/e-breuninger/terraform-provider-netbox/pull/279) by [@arjenvri](https://github.com/arjenvri))\n* resource/netbox_device: Add `primary_ipv6` attribute ([#282](https://github.com/e-breuninger/terraform-provider-netbox/pull/282) by [@arjenvri](https://github.com/arjenvri))\n* resource/netbox_virtual_machine: Add `primary_ipv6` attribute ([#283](https://github.com/e-breuninger/terraform-provider-netbox/pull/283) by [@arjenvri](https://github.com/arjenvri))\n* resource/netbox_custom_field: Add `group_name` atribute ([#280](https://github.com/e-breuninger/terraform-provider-netbox/pull/280) by [@arjenvri](https://github.com/arjenvri))\n\n## 3.0.6 (October 21st, 2022)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_contact` ([#273](https://github.com/e-breuninger/terraform-provider-netbox/pull/273) by [@arjenvri](https://github.com/arjenvri))\n* data-source/netbox_prefix: Add `description` attribute ([#277](https://github.com/e-breuninger/terraform-provider-netbox/pull/277) by [@holmesb](https://github.com/holmesb))\n* resource/netbox_cluster: Add `tenant_id` attribute ([#275](https://github.com/e-breuninger/terraform-provider-netbox/pull/275) by [@arjenvri](https://github.com/arjenvri))\n\n## 3.0.5 (October 18th, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_device_role: Add `tags` attribute ([#269](https://github.com/e-breuninger/terraform-provider-netbox/pull/269) by [@hollow](https://github.com/hollow))\n* data-source/netbox_device_role: Add `tags` attribute ([#269](https://github.com/e-breuninger/terraform-provider-netbox/pull/269) by [@hollow](https://github.com/hollow))\n\nCHANGES\n\n* resource/netbox_service: Implement provider-side validation on allowed values. Valid values are `tcp`, `udp` and `sctp`.\n\n## 3.0.4 (October 11th, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_device: Add `platform_id` attribute ([#264](https://github.com/e-breuninger/terraform-provider-netbox/pull/264) by [@mifrost](https://github.com/mifrost))\n* **New Data Source:** `netbox_prefixes ` ([#253](https://github.com/e-breuninger/terraform-provider-netbox/pull/253) by [@ironashram](https://github.com/ironashram))\n* data-source/netbox_prefix: Add `prefix`, `status`, `vlan_id`, `vlan_vid` attributes ([#253](https://github.com/e-breuninger/terraform-provider-netbox/pull/253) by [@ironashram](https://github.com/ironashram))\n* resource/netbox_device: Add `status` attribute [#266](https://github.com/e-breuninger/terraform-provider-netbox/pull/266) by [@mifrost](https://github.com/mifrost))\n\nCHANGES\n\n* resource/netbox_prefix: Deprecate `cidr` attribute in favor of new canonical `prefix` attribute\n\n## 3.0.3 (October 4th, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_site: Add `group_id` attribute ([#255](https://github.com/e-breuninger/terraform-provider-netbox/pull/255) by [@arjenvri](https://github.com/arjenvri))\n\n## 3.0.2 (September 30th, 2022)\n\nENHANCEMENTS\n\n* data-source/netbox_cluster: Add `site_id`, `cluster_type_id`, `cluster_group_id` and `tags` attribute ([#251](https://github.com/e-breuninger/terraform-provider-netbox/pull/251) by [@ns1pelle](https://github.com/ns1pelle))\n\n## 3.0.1 (September 25th, 2022)\n\nThis is a re-release of 3.0.0 because there seem to be some issues with the checksums in the 3.0.0 version.\n\n## 3.0.0 (September 23th, 2022)\n\nFEATURES\n\n* provider: Now supports NetBox v3.3\n\nENHANCEMENTS\n\n* resource/netbox_virtual_machine: In accordance with upstream API changes, VMs can now have `site_id` set directly\n* resource/netbox_virtual_machine: Add `device_id` attribute ([#238](https://github.com/e-breuninger/terraform-provider-netbox/pull/238) by [@ns1pelle](https://github.com/ns1pelle))\n* resource/netbox_circuit_termination: Add `tags` and `custom_fields` attributes ([#238](https://github.com/e-breuninger/terraform-provider-netbox/pull/238) by [@ns1pelle](https://github.com/ns1pelle))\n* resource/netbox_token: Add `allowed_ips`, `last_used` and `expires` attributes ([#238](https://github.com/e-breuninger/terraform-provider-netbox/pull/238) by [@ns1pelle](https://github.com/ns1pelle))\n* resource/netbox_device: Add `cluster_id` attribute ([#238](https://github.com/e-breuninger/terraform-provider-netbox/pull/238) by [@ns1pelle](https://github.com/ns1pelle))\n\n## 2.0.7 (September 23th, 2022)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_devices` ([#236](https://github.com/e-breuninger/terraform-provider-netbox/pull/236) by [@dipeshsharma](https://github.com/dipeshsharma))\n* provider: Add `request_timeout` attribute ([#227](https://github.com/e-breuninger/terraform-provider-netbox/pull/227) by [@twink0r](https://github.com/twink0r))\n* data-source/netbox_tenants: Add `limit` attribute to allow for larger queries\n\n## 2.0.6 (September 9th, 2022)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_site_group`\n* **New Data Source:** `netbox_site_group`\n* resource/netbox_virtual_machine: Add `status` attribute. The `status` attribute will default to `active`, which matches the implicit behavior of NetBox. If you manually changed the status of your terraform-managed NetBox VMs, be cautious\n* data-source/netbox_tenant: Allow searching by `slug` attribute\n\n## 2.0.5 (August 10th, 2022)\n\nENHANCEMENTS\n\n* provider: Update list of supported versions\n* docs: Add all missing docs and update existing ones\n* docs: Add subcategories\n\n## 2.0.4 (August 1st, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_ip_address: Add `role` attribute\n* resource/netbox_available_ip_address: improve documentation ([#220](https://github.com/e-breuninger/terraform-provider-netbox/pull/220) by [@holmesb](https://github.com/holmesb))\n\nBUG FIXES\n\n* resource/netbox_device: Set correct attribute for `device_type_id` ([#219](https://github.com/e-breuninger/terraform-provider-netbox/pull/219) by [@BegBlev](https://github.com/BegBlev))\n* data-source/netbox_ip_addresses: Use correct attribute for `role` ([#217](https://github.com/e-breuninger/terraform-provider-netbox/pull/217) by [@twink0r](https://github.com/twink0r))\n\n## 2.0.3 (July 8th, 2022)\n\nENHANCEMENTS\n\n* data-source/netbox_prefix: Add `vrf_id` attribute\n\nBUG FIXES\n\n* resource/netbox_prefix: Allow unsetting mark_utilized and is_pool attributes\n* resource/netbox_available_prefix: Allow unsetting mark_utilized and is_pool attributes\n\n## 2.0.2 (July 6th, 2022)\n\nBUG FIXES\n\n* resource/netbox_device: Make `role_id` and `site_id` attributes mandatory\n* resource/netbox_device_type: Make `manufacturer_id` attribute mandatory\n\n## 2.0.1 (June 25th, 2022)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_location` ([#195](https://github.com/e-breuninger/terraform-provider-netbox/pull/195) by [@arjenvri](https://github.com/arjenvri))\n* resource/netbox_device: Add `location_id` attribute ([#195](https://github.com/e-breuninger/terraform-provider-netbox/pull/195) by [@arjenvri](https://github.com/arjenvri))\n\n## 2.0.0 (June 16th, 2022)\n\n**BREAKING CHANGES**\nNetBox 3.2.0 came with [breaking changes](https://docs.netbox.dev/en/stable/release-notes/version-3.2/#breaking-changes). In accordance with the upstream API, the `netbox_site` resource and data source now have an `asn_ids` attribute that replaces the `asn` attriute. Note that `asn_ids` contains **IDs** of ASN objects, not numbers.\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_asn`\n\n## 1.6.7 (June 14th, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_site: Make `status` attribute optional and default to `active` ([#187](https://github.com/e-breuninger/terraform-provider-netbox/pull/187) by [@tstarck](https://github.com/tstarck))\n* data-source/netbox_site: Add `slug` parameter to allow searching for a slug ([#187](https://github.com/e-breuninger/terraform-provider-netbox/pull/187) by [@tstarck](https://github.com/tstarck))\n* data-source/netbox_site: Include `asn`, `slug`, `comments`, `description`, `group_id`, `status`, `region_id`, `tenant_id` and `time_zone` attributes in the search result ([#187](https://github.com/e-breuninger/terraform-provider-netbox/pull/187) by [@tstarck](https://github.com/tstarck))\n* resource/netbox_vlan: Add default values to `status` and `description` attributes ([#184](https://github.com/e-breuninger/terraform-provider-netbox/pull/184) by [@tstarck](https://github.com/tstarck))\n* resource/netbox_interface: Add `enabled`, `mtu`, `mode`, `tagged_vlans` and `untagged_vlans` attributes ([#183](https://github.com/e-breuninger/terraform-provider-netbox/pull/183) by [@tstarck](https://github.com/tstarck))\n\n## 1.6.6 (May 27th, 2022)\n\nENHANCEMENTS\n\n* **New Data Source:** `netbox_device_type` ([#179](https://github.com/e-breuninger/terraform-provider-netbox/pull/179) by [@tstarck](https://github.com/tstarck))\n* **New Data Source:** `netbox_vlan` ([#180](https://github.com/e-breuninger/terraform-provider-netbox/pull/180) by [@tstarck](https://github.com/tstarck))\n* provider: Add `skip_version_check` attribute\n* provider: Update list of officially supported versions\n* resource/netbox_device_type: Add `part_number` attribute ([#179](https://github.com/e-breuninger/terraform-provider-netbox/pull/179) by [@tstarck](https://github.com/tstarck))\n\nBUG FIXES\n\n* resource/netbox_circuit: Fix bug that prevented updates from being made\n* resource/netbox_circuit_provider: Fix bug that prevented updates from being made\n\n## 1.6.5 (May 18th, 2022)\n\nENHANCEMENTS\n\n* docs: Fix critical error in usage documentation\n\n## 1.6.4 (May 18th, 2022)\n\nFEATURES\n\n* **New Resource:** `netbox_user` ([#169](https://github.com/e-breuninger/terraform-provider-netbox/pull/169) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_token` ([#169](https://github.com/e-breuninger/terraform-provider-netbox/pull/169) by [@arjenvri](https://github.com/arjenvri))\n\nENHANCEMENTS\n\n* resource/netbox_site: Add `timezone`, `latitude`, `longitude` and `custom_fields` attributes ([#168](https://github.com/e-breuninger/terraform-provider-netbox/pull/168) by [@arjenvri](https://github.com/arjenvri))\n* docs: Regenerate docs with updated tooling ([#165](https://github.com/e-breuninger/terraform-provider-netbox/pull/165) by [@d-strobel](https://github.com/d-strobel))\n\n## 1.6.3 (May 6th, 2022)\n\nFEATURES\n\n* **New Data Source:** `netbox_ip_addresses` ([#159](https://github.com/e-breuninger/terraform-provider-netbox/pull/159) by [@twink0r](https://github.com/twink0r))\n* **New Resource:** `netbox_circuit` ([#160](https://github.com/e-breuninger/terraform-provider-netbox/pull/160) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_circuit_provider` ([#160](https://github.com/e-breuninger/terraform-provider-netbox/pull/160) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_circuit_termination` ([#160](https://github.com/e-breuninger/terraform-provider-netbox/pull/160) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_circuit_type` ([#160](https://github.com/e-breuninger/terraform-provider-netbox/pull/160) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_custom_field` ([#158](https://github.com/e-breuninger/terraform-provider-netbox/pull/158) by [@chapsuk](https://github.com/chapsuk))\n\nENHANCEMENTS\n\n* resource/netbox_ip_address: Add `description` attribute ([#156](https://github.com/e-breuninger/terraform-provider-netbox/pull/156) by [@fbreckle](https://github.com/fbreckle))\n* resource/netbox_virtual_machine: Add `custom_fields` attribute ([#158](https://github.com/e-breuninger/terraform-provider-netbox/pull/158) by [@chapsuk](https://github.com/chapsuk))\n\n## 1.6.2 (Apr 11, 2022)\n\nFEATURES\n\n* **New Resource:** `netbox_rir` ([#153](https://github.com/e-breuninger/terraform-provider-netbox/pull/153) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_aggregate` ([#153](https://github.com/e-breuninger/terraform-provider-netbox/pull/153) by [@arjenvri](https://github.com/arjenvri))\n\n## 1.6.1 (Apr 8, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_site: Add `tags` and `tenant_id` attributes ([#149](https://github.com/e-breuninger/terraform-provider-netbox/pull/149) by [@arjenvri](https://github.com/arjenvri))\n\n## 1.6.0 (Apr 8, 2022)\n\nFEATURES\n\n* **New Resource:** `netbox_device` ([#142](https://github.com/e-breuninger/terraform-provider-netbox/pull/142) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_device_type` ([#142](https://github.com/e-breuninger/terraform-provider-netbox/pull/142) by [@arjenvri](https://github.com/arjenvri))\n* **New Resource:** `netbox_manufacturer` ([#142](https://github.com/e-breuninger/terraform-provider-netbox/pull/142) by [@arjenvri](https://github.com/arjenvri))\n\n## 1.5.2 (Mar 4, 2022)\n\nENHANCEMENTS\n\n* data-source/netbox_tenants: Add `tenant_group` attribute ([#129](https://github.com/e-breuninger/terraform-provider-netbox/pull/129) by [@twink0r](https://github.com/twink0r))\n\n## 1.5.1 (Feb 24, 2022)\n\nENHANCEMENTS\n\n* No longer crashes if netbox is unreachable when initialising the provider [#126](https://github.com/e-breuninger/terraform-provider-netbox/pull/126) by [@twink0r](https://github.com/twink0r)\n\n## 1.5.0 (Feb 23, 2022)\n\nFEATURES\n\n* **New Data Source:** `netbox_tenants` [#124](https://github.com/e-breuninger/terraform-provider-netbox/pull/124) by [@twink0r](https://github.com/twink0r)\n\n## 1.4.0 (Feb 21, 2022)\n\nFEATURES\n\n* **New Data Source:** `netbox_cluster_type` [#122](https://github.com/e-breuninger/terraform-provider-netbox/pull/122) by [@madnutter56](https://github.com/madnutter56)\n* **New Data Source:** `netbox_site` [#122](https://github.com/e-breuninger/terraform-provider-netbox/pull/122) by [@madnutter56](https://github.com/madnutter56)\n\n## 1.3.0 (Feb 17, 2022)\n\nFEATURES\n\n* **New Resource:** `netbox_region` ([#121](https://github.com/e-breuninger/terraform-provider-netbox/pull/121) by [@gerl1ng](https://github.com/gerl1ng))\n* **New Data Source:** `netbox_region` [#121](https://github.com/e-breuninger/terraform-provider-netbox/pull/121) by [@gerl1ng](https://github.com/gerl1ng)\n\n## 1.2.2 (Feb 9, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_virtual_machine: Now has a state migration for the `vcpus` attribute ([#120](https://github.com/e-breuninger/terraform-provider-netbox/pull/120) by [@pascal-hofmann](https://github.com/pascal-hofmann))\n\n## 1.2.1 (Jan 31, 2022)\n\nFEATURES\n\n* provider: Can now optionally pass custom HTTP headers for every request ([#116](https://github.com/e-breuninger/terraform-provider-netbox/pull/116) by [@mariuskiessling](https://github.com/mariuskiessling))\n\n## 1.2.0 (Jan 20, 2022)\n\nFEATURES\n\n* resource/netbox_available_ip_address: Can now be created in netbox_ip_ranges ([#106](https://github.com/e-breuninger/terraform-provider-netbox/pull/106) by [@holmesb](https://github.com/holmesb))\n\nENHANCEMENTS\n\n* resource/netbox_available_ip_address: fixed duplicates [#59](https://github.com/e-breuninger/terraform-provider-netbox/issues/59) ([#106](https://github.com/e-breuninger/terraform-provider-netbox/pull/106) by [@holmesb](https://github.com/holmesb))\n* resource/netbox_available_ip_address: Add `description` argument ([#106](https://github.com/e-breuninger/terraform-provider-netbox/pull/106) by [@holmesb](https://github.com/holmesb))\n* resource/netbox_available_ip_address: `status` argument is now optional ([#106](https://github.com/e-breuninger/terraform-provider-netbox/pull/106) by [@holmesb](https://github.com/holmesb))\n* resource/netbox_vrf: Add `tenant_id` attribute ([#112](https://github.com/e-breuninger/terraform-provider-netbox/pull/112) by [@cova-fe](https://github.com/cova-fe))\n* data-source/netbox_vrf: Add `tenant_id` attribute ([#112](https://github.com/e-breuninger/terraform-provider-netbox/pull/112) by [@cova-fe](https://github.com/cova-fe))\n* resource/available_prefix: Add `mark_utilized` attribute ([#111](https://github.com/e-breuninger/terraform-provider-netbox/pull/111) by [@cova-fe](https://github.com/cova-fe))\n\n## 1.1.0 (Jan 3, 2022)\n\nFEATURES\n\n* provider: Now supports NetBox v3.1.3\n\n## 1.0.2 Ho-Ho-Ho (Dec 24, 2021)\n\nENHANCEMENTS\n\n* resource/tag: Add `description` attribute ([#98](https://github.com/e-breuninger/terraform-provider-netbox/pull/98)) by [@lu1as](https://github.com/lu1as))\n\n## 1.0.1 (Dec 23, 2021)\n\nFEATURES\n\n* **New Resource:** `netbox_ip_range` ([#101](https://github.com/e-breuninger/terraform-provider-netbox/pull/100) by [@holmesb](https://github.com/holmesb))\n* **New Data Source:** `netbox_ip_range` ([#101](https://github.com/e-breuninger/terraform-provider-netbox/pull/100) by [@holmesb](https://github.com/holmesb))\n \n## 1.0.0 (Nov 8, 2021)\n\nFEATURES\n\n* provider: Now supports NetBox v3.0.9\n\nBREAKING CHANGES\n\n* resource/virtual_machine: `vcpus` is now a float to match upstream API\n\n## 0.3.2 (Nov 2, 2021)\n\nENHANCEMENTS\n\n* resource/primary_ip: Support both v4 and v6 primary IP ([#87](https://github.com/e-breuninger/terraform-provider-netbox/pull/87) by [@t-tran](https://github.com/t-tran))\n\n## 0.3.1 (Oct 27, 2021)\n\nFEATURES\n\n* **New Resource:** `netbox_vlan` ([#83](https://github.com/e-breuninger/terraform-provider-netbox/pull/83) by [@Sanverik](https://github.com/Sanverik))\n* **New Resource:** `netbox_ipam_role` ([#86](https://github.com/e-breuninger/terraform-provider-netbox/pull/86) by [@Sanverik](https://github.com/Sanverik))\n\nENHANCEMENTS\n\n* resource/prefix: Add `site_id`, `vlan_id` and `role_id` attributes ([#85](https://github.com/e-breuninger/terraform-provider-netbox/pull/85) and [#85](https://github.com/e-breuninger/terraform-provider-netbox/pull/85)) by [@Sanverik](https://github.com/Sanverik))\n\n## 0.3.0 (Oct 19, 2021)\n\nFEATURES\n\n* provider: Now supports NetBox v2.11.12\n\nBREAKING CHANGES\n\n* resource/virtual_machine: `vcpus` is now a string to match upstream API\n\n## 0.2.5 (Oct 8, 2021)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_site` ([#78](https://github.com/e-breuninger/terraform-provider-netbox/pull/78))\n\nBUG FIXES\n\n* resource/cluster: Properly set tags when updating ([#69](https://github.com/e-breuninger/terraform-provider-netbox/issues/69))\n\n## 0.2.4 (Sep 20, 2021)\n\nCHANGES\n\n* Use go 1.17 to fix some builds\n\n## 0.2.3 (Sep 20, 2021)\n\nENHANCEMENTS\n\n* Add arm64 builds ([#71](https://github.com/e-breuninger/terraform-provider-netbox/pull/71) by [@richardklose](https://github.com/richardklose))\n\n## 0.2.2 (Aug 23, 2021)\n\nENHANCEMENTS\n\n* resource/interface: Add `mac_address` attribute ([#65](https://github.com/e-breuninger/terraform-provider-netbox/pull/65) by [@holmesb](https://github.com/holmesb))\n\n## 0.2.1 (Jul 26, 2021)\n\nENHANCEMENTS\n\n* resource/prefix: Add `vrf` and `tenant` attribute ([#61](https://github.com/e-breuninger/terraform-provider-netbox/pull/61) by [@jeansebastienh](https://github.com/jeansebastienh))\n\nBUG FIXES\n\n* resource/prefix: Correctly read `prefix` and `status` ([#60](https://github.com/e-breuninger/terraform-provider-netbox/pull/60) by [@jeansebastienh](https://github.com/jeansebastienh))\n\n## 0.2.0 (May 31, 2021)\n\nFEATURES\n\n* provider: Now supports NetBox v2.10.10\n\nCHANGES\n\n* resource/service: `port` field is now deprecated in favor of `ports` field.\n\n## 0.1.3 (May 17, 2021)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_tenant_group` ([#48](https://github.com/e-breuninger/terraform-provider-netbox/pull/48) by [@pezhore](https://github.com/pezhore))\n* **New Data Source:** `netbox_tenant_group` ([#48](https://github.com/e-breuninger/terraform-provider-netbox/pull/48) by [@pezhore](https://github.com/pezhore))\n* data-source/tenant: Add `group_id` attribute ([#48](https://github.com/e-breuninger/terraform-provider-netbox/pull/48) by [@pezhore](https://github.com/pezhore))\n\n## 1.5.1 (Feb 24, 2022)\n\nENHANCEMENTS\n\n* No longer crashes if netbox is unreachable when initialising the provider [#126](https://github.com/e-breuninger/terraform-provider-netbox/pull/126) by [@twink0r](https://github.com/twink0r)\n\n## 1.5.0 (Feb 23, 2022)\n\nFEATURES\n\n* **New Data Source:** `netbox_tenants` [#124](https://github.com/e-breuninger/terraform-provider-netbox/pull/124) by [@twink0r](https://github.com/twink0r)\n\n## 1.4.0 (Feb 21, 2022)\n\nFEATURES\n\n* **New Data Source:** `netbox_cluster_type` [#122](https://github.com/e-breuninger/terraform-provider-netbox/pull/122) by [@madnutter56](https://github.com/madnutter56)\n* **New Data Source:** `netbox_site` [#122](https://github.com/e-breuninger/terraform-provider-netbox/pull/122) by [@madnutter56](https://github.com/madnutter56)\n\n## 1.3.0 (Feb 17, 2022)\n\nFEATURES\n\n* **New Resource:** `netbox_region` ([#121](https://github.com/e-breuninger/terraform-provider-netbox/pull/121) by [@gerl1ng](https://github.com/gerl1ng))\n* **New Data Source:** `netbox_region` [#121](https://github.com/e-breuninger/terraform-provider-netbox/pull/121) by [@gerl1ng](https://github.com/gerl1ng)\n\n## 1.2.2 (Feb 9, 2022)\n\nENHANCEMENTS\n\n* resource/netbox_virtual_machine: Now has a state migration for the `vcpus` attribute ([#120](https://github.com/e-breuninger/terraform-provider-netbox/pull/120) by [@pascal-hofmann](https://github.com/pascal-hofmann))\n\n## 1.2.1 (Jan 31, 2022)\n\nFEATURES\n\n* provider: Can now optionally pass custom HTTP headers for every request ([#116](https://github.com/e-breuninger/terraform-provider-netbox/pull/116) by [@mariuskiessling](https://github.com/mariuskiessling))\n\n## 1.2.0 (Jan 20, 2022)\n\nFEATURES\n\n* resource/netbox_available_ip_address: Can now be created in netbox_ip_ranges ([#106](https://github.com/e-breuninger/terraform-provider-netbox/pull/106) by [@holmesb](https://github.com/holmesb))\n\nENHANCEMENTS\n\n* resource/netbox_available_ip_address: fixed duplicates [#59](https://github.com/e-breuninger/terraform-provider-netbox/issues/59) ([#106](https://github.com/e-breuninger/terraform-provider-netbox/pull/106) by [@holmesb](https://github.com/holmesb))\n* resource/netbox_available_ip_address: Add `description` argument ([#106](https://github.com/e-breuninger/terraform-provider-netbox/pull/106) by [@holmesb](https://github.com/holmesb))\n* resource/netbox_available_ip_address: `status` argument is now optional ([#106](https://github.com/e-breuninger/terraform-provider-netbox/pull/106) by [@holmesb](https://github.com/holmesb))\n* resource/netbox_vrf: Add `tenant_id` attribute ([#112](https://github.com/e-breuninger/terraform-provider-netbox/pull/112) by [@cova-fe](https://github.com/cova-fe))\n* data-source/netbox_vrf: Add `tenant_id` attribute ([#112](https://github.com/e-breuninger/terraform-provider-netbox/pull/112) by [@cova-fe](https://github.com/cova-fe))\n* resource/available_prefix: Add `mark_utilized` attribute ([#111](https://github.com/e-breuninger/terraform-provider-netbox/pull/111) by [@cova-fe](https://github.com/cova-fe))\n\n## 1.1.0 (Jan 3, 2022)\n\nFEATURES\n\n* provider: Now supports NetBox v3.1.3\n\n## 1.0.2 Ho-Ho-Ho (Dec 24, 2021)\n\nENHANCEMENTS\n\n* resource/tag: Add `description` attribute ([#98](https://github.com/e-breuninger/terraform-provider-netbox/pull/98)) by [@lu1as](https://github.com/lu1as))\n\n## 1.0.1 (Dec 23, 2021)\n\nFEATURES\n\n* **New Resource:** `netbox_ip_range` ([#101](https://github.com/e-breuninger/terraform-provider-netbox/pull/100) by [@holmesb](https://github.com/holmesb))\n* **New Data Source:** `netbox_ip_range` ([#101](https://github.com/e-breuninger/terraform-provider-netbox/pull/100) by [@holmesb](https://github.com/holmesb))\n \n## 1.0.0 (Nov 8, 2021)\n\nFEATURES\n\n* provider: Now supports NetBox v3.0.9\n\nBREAKING CHANGES\n\n* resource/virtual_machine: `vcpus` is now a float to match upstream API\n\n## 0.3.2 (Nov 2, 2021)\n\nENHANCEMENTS\n\n* resource/primary_ip: Support both v4 and v6 primary IP ([#87](https://github.com/e-breuninger/terraform-provider-netbox/pull/87) by [@t-tran](https://github.com/t-tran))\n\n## 0.3.1 (Oct 27, 2021)\n\nFEATURES\n\n* **New Resource:** `netbox_vlan` ([#83](https://github.com/e-breuninger/terraform-provider-netbox/pull/83) by [@Sanverik](https://github.com/Sanverik))\n* **New Resource:** `netbox_ipam_role` ([#86](https://github.com/e-breuninger/terraform-provider-netbox/pull/86) by [@Sanverik](https://github.com/Sanverik))\n\nENHANCEMENTS\n\n* resource/prefix: Add `site_id`, `vlan_id` and `role_id` attributes ([#85](https://github.com/e-breuninger/terraform-provider-netbox/pull/85) and [#85](https://github.com/e-breuninger/terraform-provider-netbox/pull/85)) by [@Sanverik](https://github.com/Sanverik))\n\n## 0.3.0 (Oct 19, 2021)\n\nFEATURES\n\n* provider: Now supports NetBox v2.11.12\n\nBREAKING CHANGES\n\n* resource/virtual_machine: `vcpus` is now a string to match upstream API\n\n## 0.2.5 (Oct 8, 2021)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_site` ([#78](https://github.com/e-breuninger/terraform-provider-netbox/pull/78))\n\nBUG FIXES\n\n* resource/cluster: Properly set tags when updating ([#69](https://github.com/e-breuninger/terraform-provider-netbox/issues/69))\n\n## 0.2.4 (Sep 20, 2021)\n\nCHANGES\n\n* Use go 1.17 to fix some builds\n\n## 0.2.3 (Sep 20, 2021)\n\nENHANCEMENTS\n\n* Add arm64 builds ([#71](https://github.com/e-breuninger/terraform-provider-netbox/pull/71) by [@richardklose](https://github.com/richardklose))\n\n## 0.2.2 (Aug 23, 2021)\n\nENHANCEMENTS\n\n* resource/interface: Add `mac_address` attribute ([#65](https://github.com/e-breuninger/terraform-provider-netbox/pull/65) by [@holmesb](https://github.com/holmesb))\n\n## 0.2.1 (Jul 26, 2021)\n\nENHANCEMENTS\n\n* resource/prefix: Add `vrf` and `tenant` attribute ([#61](https://github.com/e-breuninger/terraform-provider-netbox/pull/61) by [@jeansebastienh](https://github.com/jeansebastienh))\n\nBUG FIXES\n\n* resource/prefix: Correctly read `prefix` and `status` ([#60](https://github.com/e-breuninger/terraform-provider-netbox/pull/60) by [@jeansebastienh](https://github.com/jeansebastienh))\n\n## 0.2.0 (May 31, 2021)\n\nFEATURES\n\n* provider: Now supports NetBox v2.10.10\n\nCHANGES\n\n* resource/service: `port` field is now deprecated in favor of `ports` field.\n\n## 0.1.3 (May 17, 2021)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_tenant_group` ([#48](https://github.com/e-breuninger/terraform-provider-netbox/pull/48) by [@pezhore](https://github.com/pezhore))\n* **New Data Source:** `netbox_tenant_group` ([#48](https://github.com/e-breuninger/terraform-provider-netbox/pull/48) by [@pezhore](https://github.com/pezhore))\n* data-source/tenant: Add `group_id` attribute ([#48](https://github.com/e-breuninger/terraform-provider-netbox/pull/48) by [@pezhore](https://github.com/pezhore))\n* resource/tenant: Add `group_id` attribute ([#48](https://github.com/e-breuninger/terraform-provider-netbox/pull/48) by [@pezhore](https://github.com/pezhore))\n* Documentation ([#46](https://github.com/e-breuninger/terraform-provider-netbox/pull/46) by [@pezhore](https://github.com/pezhore))\n\n## 0.1.2 (May 4, 2021)\n\nENHANCEMENTS\n\n* **New Resource:** `netbox_prefix` ([#43](https://github.com/e-breuninger/terraform-provider-netbox/pull/43) by [@pezhore](https://github.com/pezhore))\n* **New Data Source:** `netbox_prefix` ([#43](https://github.com/e-breuninger/terraform-provider-netbox/pull/43) by [@pezhore](https://github.com/pezhore))\n* **New Resource:** `netbox_available_ip_address` ([#43](https://github.com/e-breuninger/terraform-provider-netbox/pull/43) by [@pezhore](https://github.com/pezhore))\n\n## 0.1.1 (February 15, 2021)\n\nENHANCEMENTS\n\n* data-source/netbox_virtual_machines: Add `limit` attribute ([#33](https://github.com/e-breuninger/terraform-provider-netbox/pull/33) by [@jake2184](https://github.com/jake2184))\n\n## 0.1.0 Ho-Ho-Ho (December 24, 2020)\n\nFEATURES\n\n* **New Resource:** `netbox_vrf` ([#26](https://github.com/e-breuninger/terraform-provider-netbox/pull/26) by [@rthomson](https://github.com/rthomson))\n* **New Data Source:** `netbox_vrf` ([#26](https://github.com/e-breuninger/terraform-provider-netbox/pull/26) by [@rthomson](https://github.com/rthomson))\n* **New Resource:** `netbox_cluster_group`\n* **New Data Source:** `netbox_cluster_group`\n\nENHANCEMENTS\n\n* resource/netbox_ip_address: Add `tenant_id` attribute\n* resource/netbox_cluster: Add `cluster_group_id` attribute\n\n## 0.0.9 (November 20, 2020)\n\nFEATURES\n\n* **New Data Source:** `netbox_interfaces` ([#9](https://github.com/e-breuninger/terraform-provider-netbox/pull/9) by [@jake2184](https://github.com/jake2184))\n\nBUG FIXES\n\n* provider: Honor Sub-Paths in netbox URL ([#15](https://github.com/e-breuninger/terraform-provider-netbox/pull/15) by [@kasimon](https://github.com/kasimon))\n\n## 0.0.8 (November 19, 2020)\n\nFEATURES\n\n* **New Data Source:** `netbox_virtual_machines` ([#8](https://github.com/e-breuninger/terraform-provider-netbox/pull/8) by [@jake2184](https://github.com/jake2184))\n"
  },
  {
    "path": "GNUmakefile",
    "content": "TEST?=netbox/*.go\nTEST_FUNC?=TestAccNetboxMACAddr*\nGOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor)\nDOCKER_COMPOSE=docker compose\n\nexport NETBOX_VERSION=v4.4.10\nexport NETBOX_SERVER_URL=http://localhost:8001\nexport NETBOX_API_TOKEN=0123456789abcdef0123456789abcdef01234567\nexport NETBOX_TOKEN=$(NETBOX_API_TOKEN)\n\ndefault: testacc\n\n# Run acceptance tests\n.PHONY: testacc\ntestacc: docker-up\n\t@echo \"⌛ Startup acceptance tests on $(NETBOX_SERVER_URL) with version $(NETBOX_VERSION)\"\n\tTF_ACC=1 go test -timeout 20m -v -cover $(TEST)\n\n.PHONY: testacc-specific-test\ntestacc-specific-test: # docker-up\n\t@echo \"⌛ Startup acceptance tests on $(NETBOX_SERVER_URL) with version $(NETBOX_VERSION)\"\n\t@echo \"⌛ Testing function $(TEST_FUNC)\"\n\tTF_ACC=1 go test -timeout 20m -v -cover $(TEST) -run $(TEST_FUNC)\n\n.PHONY: test\ntest:\n\tgo test $(TEST) $(TESTARGS) -timeout=120s -parallel=4 -cover\n\n# Run dockerized Netbox for acceptance testing\n.PHONY: docker-up\ndocker-up:\n\t@echo \"⌛ Startup Netbox $(NETBOX_VERSION) and wait for service to become ready\"\n\t$(DOCKER_COMPOSE) -f docker/docker-compose.yml up --build wait\n\t$(DOCKER_COMPOSE) -f docker/docker-compose.yml logs\n\t@echo \"🚀 Netbox is up and running!\"\n\n.PHONY: docker-logs\ndocker-logs:\n\t$(DOCKER_COMPOSE) -f docker/docker-compose.yml logs\n\n.PHONY: docker-down\ndocker-down:\n\t$(DOCKER_COMPOSE) -f docker/docker-compose.yml down --volumes\n\n.PHONY: docs\ndocs:\n\tNETBOX_API_TOKEN=\"\" NETBOX_SERVER_URL=\"\" go generate ./...\n\n#! Development\n# The following make goals are only for local usage\n.PHONY: fmt\nfmt:\n\tgo fmt\n\tgo fmt netbox/*.go\n"
  },
  {
    "path": "LICENSE",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in\n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "README.md",
    "content": "# terraform-provider-netbox\n\nThe Terraform Netbox provider is a plugin for Terraform that allows for the full lifecycle management of [Netbox](https://netboxlabs.com/docs/netbox/) resources.\nThis provider is maintained by E. Breuninger.\n\nSee: [Official documentation](https://registry.terraform.io/providers/e-breuninger/netbox/latest/docs) in the Terraform registry.\n\n## Requirements\n\n- [Terraform](https://www.terraform.io/downloads.html) >= 0.12.x\n\n## Supported netbox versions\n\nNetbox often makes breaking API changes even in non-major releases. Check the table below to see which version a provider was tested against. It is generally recommended to use the provider version matching your Netbox version. We aim to always support the latest minor version of Netbox.\n\nSince version [1.6.6](https://github.com/e-breuninger/terraform-provider-netbox/commit/0b0b2fffa54d4ab2e5f1677e948b01e56ba211c8), each version of the provider has a built-in list of all Netbox versions it supports at release time. Upon initialization, the provider will probe your Netbox version and include a (non-blocking) warning if the used Netbox version is not supported.\n\n| Netbox version  | Provider version |\n| --------------- | ---------------- |\n| v4.3.0 - 4.4.10 | v5.0.0 and up    |\n| v4.2.2 - 4.2.9  | v4.0.0 - 4.3.1   |\n| v4.1.0 - 4.1.11 | v3.10.0 - 3.11.1 |\n| v4.0.0 - 4.0.11 | v3.9.0 - 3.9.2   |\n| v3.7.0 - 3.7.8  | v3.8.0 - 3.8.9   |\n| v3.6.0 - 3.6.9  | v3.7.0 - 3.7.7   |\n| v3.5.1 - 3.5.9  | v3.6.x           |\n| v3.4.3 - 3.4.10 | v3.5.x           |\n| v3.3.0 - 3.4.2  | v3.0.x - 3.5.1   |\n| v3.2.0 - 3.2.9  | v2.0.x           |\n| v3.1.9          | v1.6.0 - 1.6.7   |\n| v3.1.3          | v1.1.x - 1.5.2   |\n| v3.0.9          | v1.0.x           |\n| v2.11.12        | v0.3.x           |\n| v2.10.10        | v0.2.x           |\n| v2.9            | v0.1.x           |\n\n## Building The Provider\n\n1. Clone the repository\n1. Enter the repository directory\n1. Build the provider using the Go `install` command:\n\n```sh\ngo install\n```\n\n## Installation\n\nStarting with Terraform 0.13, you can download the provider via the Terraform registry.\n\nFor further information on how to use third party providers, see the [Terraform documentation](https://www.terraform.io/docs/configuration/providers.html)\n\nReleases for all major plattforms are available on the release page.\n\n## Using the provider\n\nHere is a short example on how to use this provider:\n\n```hcl\nprovider \"netbox\" {\n  server_url = \"https://demo.netbox.dev\"\n  api_token  = \"<your api token>\"\n}\n\nresource \"netbox_platform\" \"testplatform\" {\n  name = \"my-test-platform\"\n}\n```\n\nFor a more examples, see the [provider documentation](https://registry.terraform.io/providers/e-breuninger/netbox/latest/docs).\n\n## Developing the Provider\n\nIf you wish to work on the provider, you need [Go](http://www.golang.org) installed on your machine.\n\nTo compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.\n\nTo generate or update documentation, run `make docs`.\n\nIn order to run the suite of unit tests, run `make test`.\n\nIn order to run the full suite of acceptance tests, run `make testacc`.\n\nIn order to run a single specific acceptance test, run\n\n```sh\nTEST_FUNC=<test_name> make testacc-specific-test\n```\n\nFor example:\n\n```sh\nTEST_FUNC=TestAccNetboxLocationDataSource_basic make testacc-specific-test\n```\n\n_Note:_ Acceptance tests create a docker compose stack on port 8001.\n\n```sh\nmake testacc\n```\n\nIf you notice a failed test, it might be due to a stale netbox data volume. Before concluding there is a problem,\nrefresh the docker containers by running `docker-compose down --volumes` in the `docker` directory. Then run the tests again.\n\nIf you get `too many open files` errors when running the acceptance test suite locally on Linux, your user limit for open file descriptors might be too low. You can increase that limit with `ulimit -n 2048`.\n\n## Contribution\n\nWe focus on virtual machine management and IPAM. If you want to contribute more resources to this provider, feel free to make a PR.\n"
  },
  {
    "path": "docker/Dockerfile-wait",
    "content": "FROM alpine\nCOPY wait-for /usr/local/bin\n"
  },
  {
    "path": "docker/docker-compose.yml",
    "content": "---\nservices:\n  postgres:\n    image: postgres:18-alpine\n    environment:\n      - POSTGRES_USER=netbox\n      - POSTGRES_PASSWORD=netbox\n      - POSTGRES_DB=netbox\n  redis:\n    image: docker.io/valkey/valkey:9.0-alpine\n  netbox:\n    image: netboxcommunity/netbox:${NETBOX_VERSION}\n    depends_on:\n      - postgres\n      - redis\n    ports:\n      - 8001:8080\n    environment:\n      - CORS_ORIGIN_ALLOW_ALL=True\n      - DB_NAME=netbox\n      - DB_USER=netbox\n      - DB_PASSWORD=netbox\n      - DB_HOST=postgres\n      - REDIS_HOST=redis\n      - REDIS_DATABASE=0\n      - REDIS_SSL=false\n      - REDIS_CACHE_HOST=redis\n      - REDIS_CACHE_DATABASE=1\n      - REDIS_CACHE_SSL=false\n      - SECRET_KEY=0123456789abcdefghij0123456789abcdefghij0123456789\n      - SKIP_STARTUP_SCRIPTS=false\n      - SKIP_SUPERUSER=false\n      - SUPERUSER_NAME=admin\n      - SUPERUSER_EMAIL=admin@example.com\n      - SUPERUSER_PASSWORD=admin\n      - SUPERUSER_API_TOKEN=${NETBOX_API_TOKEN}\n      - METRICS_ENABLED=true\n      - API_TOKEN_PEPPER_1=D1)T@tb@cRf(guHO1q+rs&zrXKKA=96uQU3bT_N8t0NNo5mHy2\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8080/metrics\"]\n      interval: 10s\n      timeout: 10s\n      retries: 10\n      start_period: 5s\n\n  wait:\n    build:\n      context: .\n      dockerfile: Dockerfile-wait\n    depends_on:\n      - netbox\n    command: wait-for netbox:8080 --timeout 240 -- echo \"Netbox is up and running\"\n"
  },
  {
    "path": "docker/wait-for",
    "content": "#!/bin/sh\n\n# Source: https://raw.githubusercontent.com/eficode/wait-for/master/wait-for\n\n# The MIT License (MIT)\n#\n# Copyright (c) 2017 Eficode Oy\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\nVERSION=\"2.2.4\"\n\nset -- \"$@\" -- \"$TIMEOUT\" \"$QUIET\" \"$PROTOCOL\" \"$HOST\" \"$PORT\" \"$result\"\nTIMEOUT=15\nQUIET=0\n# The protocol to make the request with, either \"tcp\" or \"http\"\nPROTOCOL=\"tcp\"\n\nechoerr() {\n    if [ \"$QUIET\" -ne 1 ]; then printf \"%s\\n\" \"$*\" 1>&2; fi\n}\n\nusage() {\n    exitcode=\"$1\"\n    cat <<USAGE >&2\nUsage:\n  $0 host:port|url [-t timeout] [-- command args]\n  -q | --quiet                        Do not output any status messages\n  -t TIMEOUT | --timeout=timeout      Timeout in seconds, zero for no timeout\n                                      Defaults to 15 seconds\n  -v | --version                      Show the version of this tool\n  -- COMMAND ARGS                     Execute command with args after the test finishes\nUSAGE\n    exit \"$exitcode\"\n}\n\nwait_for() {\n    case \"$PROTOCOL\" in\n    tcp)\n        if ! command -v nc >/dev/null; then\n            echoerr 'nc command is missing!'\n            exit 1\n        fi\n        ;;\n    http)\n        if ! command -v wget >/dev/null; then\n            echoerr 'wget command is missing!'\n            exit 1\n        fi\n        ;;\n    esac\n\n    TIMEOUT_END=$(($(date +%s) + TIMEOUT))\n\n    while :; do\n        case \"$PROTOCOL\" in\n        tcp)\n            nc -w 1 -z \"$HOST\" \"$PORT\" >/dev/null 2>&1\n            ;;\n        http)\n            wget --timeout=1 --tries=1 -q \"$HOST\" -O /dev/null >/dev/null 2>&1\n            ;;\n        *)\n            echoerr \"Unknown protocol '$PROTOCOL'\"\n            exit 1\n            ;;\n        esac\n\n        result=$?\n\n        if [ $result -eq 0 ]; then\n            if [ $# -gt 7 ]; then\n                for result in $(seq $(($# - 7))); do\n                    result=$1\n                    shift\n                    set -- \"$@\" \"$result\"\n                done\n\n                TIMEOUT=$2 QUIET=$3 PROTOCOL=$4 HOST=$5 PORT=$6 result=$7\n                shift 7\n                exec \"$@\"\n            fi\n            exit 0\n        fi\n\n        if [ \"$TIMEOUT\" -ne 0 ] && [ \"$(date +%s)\" -ge \"$TIMEOUT_END\" ]; then\n            echo \"Operation timed out\" >&2\n            exit 1\n        fi\n\n        sleep 1\n    done\n}\n\nwhile :; do\n    case \"$1\" in\n    http://* | https://*)\n        HOST=\"$1\"\n        PROTOCOL=\"http\"\n        shift 1\n        ;;\n    *:*)\n        HOST=$(printf \"%s\\n\" \"$1\" | cut -d : -f 1)\n        PORT=$(printf \"%s\\n\" \"$1\" | cut -d : -f 2)\n        shift 1\n        ;;\n    -v | --version)\n        echo $VERSION\n        exit\n        ;;\n    -q | --quiet)\n        QUIET=1\n        shift 1\n        ;;\n    -q-*)\n        QUIET=0\n        echoerr \"Unknown option: $1\"\n        usage 1\n        ;;\n    -q*)\n        QUIET=1\n        result=$1\n        shift 1\n        set -- -\"${result#-q}\" \"$@\"\n        ;;\n    -t | --timeout)\n        TIMEOUT=\"$2\"\n        shift 2\n        ;;\n    -t*)\n        TIMEOUT=\"${1#-t}\"\n        shift 1\n        ;;\n    --timeout=*)\n        TIMEOUT=\"${1#*=}\"\n        shift 1\n        ;;\n    --)\n        shift\n        break\n        ;;\n    --help)\n        usage 0\n        ;;\n    -*)\n        QUIET=0\n        echoerr \"Unknown option: $1\"\n        usage 1\n        ;;\n    *)\n        QUIET=0\n        echoerr \"Unknown argument: $1\"\n        usage 1\n        ;;\n    esac\ndone\n\nif ! [ \"$TIMEOUT\" -ge 0 ] 2>/dev/null; then\n    echoerr \"Error: invalid timeout '$TIMEOUT'\"\n    usage 3\nfi\n\ncase \"$PROTOCOL\" in\ntcp)\n    if [ \"$HOST\" = \"\" ] || [ \"$PORT\" = \"\" ]; then\n        echoerr \"Error: you need to provide a host and port to test.\"\n        usage 2\n    fi\n    ;;\nhttp)\n    if [ \"$HOST\" = \"\" ]; then\n        echoerr \"Error: you need to provide a host to test.\"\n        usage 2\n    fi\n    ;;\nesac\n\nwait_for \"$@\"\n"
  },
  {
    "path": "docs/data-sources/asn.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_asn Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_asn (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_asn\" \"asn_1\" {\n  asn = \"1111\"\n  tag = \"tag-1\"\n}\n\ndata \"netbox_asn\" \"asn_2\" {\n  tag    = \"tag-1\"\n  tag__n = \"tag-2\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `asn` (String) At least one of `asn` or `tag` must be given.\n- `tag` (String) Tag to include in the data source filter (must match the tag's slug). At least one of `asn` or `tag` must be given.\n- `tag__n` (String) Tag to exclude from the data source filter (must match the tag's slug).\nRefer to [Netbox's documentation](https://demo.netbox.dev/static/docs/rest-api/filtering/#lookup-expressions)\nfor more information on available lookup expressions.\n\n### Read-Only\n\n- `description` (String)\n- `id` (Number) The ID of this resource.\n- `tags` (Set of String)\n\n\n"
  },
  {
    "path": "docs/data-sources/asns.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_asns Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_asns (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_asns\" \"asns\" {\n  filter {\n    name  = \"asn__gte\"\n    value = \"1000\"\n  }\n  filter {\n    name  = \"asn__lte\"\n    value = \"2000\"\n  }\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `asns` (List of Object) (see [below for nested schema](#nestedatt--asns))\n- `id` (String) The ID of this resource.\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--asns\"></a>\n### Nested Schema for `asns`\n\nRead-Only:\n\n- `asn` (Number)\n- `id` (Number)\n- `rir_id` (Number)\n- `tags` (Set of String)\n\n\n"
  },
  {
    "path": "docs/data-sources/available_prefix.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_available_prefix Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_available_prefix (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `prefix_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `prefixes_available` (List of Object) (see [below for nested schema](#nestedatt--prefixes_available))\n\n<a id=\"nestedatt--prefixes_available\"></a>\n### Nested Schema for `prefixes_available`\n\nRead-Only:\n\n- `family` (Number)\n- `prefix` (String)\n- `vrf_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/cluster.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_cluster Data Source - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  \n---\n\n# netbox_cluster (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `cluster_group_id` (Number)\n- `id` (String) At least one of `name`, `site_id` or `id` must be given.\n- `name` (String) At least one of `name`, `site_id` or `id` must be given.\n- `site_id` (Number) At least one of `name`, `site_id` or `id` must be given.\n\n### Read-Only\n\n- `cluster_id` (Number)\n- `cluster_type_id` (Number)\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `location_id` (Number)\n- `region_id` (Number)\n- `scope_id` (Number)\n- `scope_type` (String)\n- `site_group_id` (Number)\n- `tags` (Set of String)\n\n\n"
  },
  {
    "path": "docs/data-sources/cluster_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_cluster_group Data Source - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  \n---\n\n# netbox_cluster_group (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_cluster_group\" \"dc_west\" {\n  name = \"dc-west\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Read-Only\n\n- `cluster_group_id` (Number)\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/cluster_type.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_cluster_type Data Source - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  \n---\n\n# netbox_cluster_type (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Read-Only\n\n- `cluster_type_id` (Number)\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/clusters.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_clusters Data Source - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  \n---\n\n# netbox_clusters (Data Source)\n\n\n\n## Example Usage\n\n```terraform\n// Get all clusters of a specific type\ndata \"netbox_cluster_type\" \"vmware\" {\n  name = \"VMware ESXi\"\n}\n\ndata \"netbox_clusters\" \"vmware_clusters\" {\n  filter {\n    name  = \"cluster_type_id\"\n    value = data.netbox_cluster_type.vmware.id\n  }\n}\n\n// Get clusters by name regex\ndata \"netbox_clusters\" \"prod_clusters\" {\n  name_regex = \"prod-.*\"\n}\n\n// Get clusters at a specific site\ndata \"netbox_clusters\" \"site_clusters\" {\n  filter {\n    name  = \"site_id\"\n    value = data.netbox_site.main.id\n  }\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n- `name_regex` (String)\n\n### Read-Only\n\n- `clusters` (List of Object) (see [below for nested schema](#nestedatt--clusters))\n- `id` (String) The ID of this resource.\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--clusters\"></a>\n### Nested Schema for `clusters`\n\nRead-Only:\n\n- `cluster_group_id` (Number)\n- `cluster_id` (Number)\n- `cluster_type_id` (Number)\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `location_id` (Number)\n- `name` (String)\n- `region_id` (Number)\n- `scope_id` (Number)\n- `scope_type` (String)\n- `site_group_id` (Number)\n- `site_id` (Number)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/config_context.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_config_context Data Source - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  \n---\n\n# netbox_config_context (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Read-Only\n\n- `cluster_groups` (List of Number)\n- `cluster_types` (List of Number)\n- `clusters` (List of Number)\n- `data` (String)\n- `description` (String)\n- `device_types` (List of Number)\n- `id` (String) The ID of this resource.\n- `locations` (List of Number)\n- `platforms` (List of Number)\n- `regions` (List of Number)\n- `roles` (List of Number)\n- `site_groups` (List of Number)\n- `sites` (List of Number)\n- `tags` (List of String)\n- `tenant_groups` (List of Number)\n- `tenants` (List of Number)\n- `weight` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/contact.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_contact Data Source - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  \n---\n\n# netbox_contact (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `description` (String)\n- `name` (String) At least one of `name` or `slug` must be given.\n- `slug` (String) At least one of `name` or `slug` must be given.\n\n### Read-Only\n\n- `group_id` (Number)\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/contact_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_contact_group Data Source - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  \n---\n\n# netbox_contact_group (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Read-Only\n\n- `description` (String)\n- `id` (String) The ID of this resource.\n- `parent_id` (Number)\n- `slug` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/contact_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_contact_role Data Source - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  \n---\n\n# netbox_contact_role (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `name` (String) At least one of `name` or `slug` must be given.\n- `slug` (String) At least one of `name` or `slug` must be given.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/device_interfaces.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_interfaces Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_device_interfaces (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n- `name_regex` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `interfaces` (List of Object) (see [below for nested schema](#nestedatt--interfaces))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--interfaces\"></a>\n### Nested Schema for `interfaces`\n\nRead-Only:\n\n- `description` (String)\n- `device_id` (Number)\n- `enabled` (Boolean)\n- `id` (Number)\n- `mac_address` (String)\n- `mac_addresses` (Set of Object) (see [below for nested schema](#nestedobjatt--interfaces--mac_addresses))\n- `mode` (Map of String)\n- `mtu` (Number)\n- `name` (String)\n- `tag_ids` (List of Number)\n- `tagged_vlans` (List of Object) (see [below for nested schema](#nestedobjatt--interfaces--tagged_vlans))\n- `type` (String)\n- `untagged_vlan` (List of Object) (see [below for nested schema](#nestedobjatt--interfaces--untagged_vlan))\n\n<a id=\"nestedobjatt--interfaces--mac_addresses\"></a>\n### Nested Schema for `interfaces.mac_addresses`\n\nRead-Only:\n\n- `description` (String)\n- `id` (Number)\n- `mac_address` (String)\n\n\n<a id=\"nestedobjatt--interfaces--tagged_vlans\"></a>\n### Nested Schema for `interfaces.tagged_vlans`\n\nRead-Only:\n\n- `id` (Number)\n- `name` (String)\n- `vid` (Number)\n\n\n<a id=\"nestedobjatt--interfaces--untagged_vlan\"></a>\n### Nested Schema for `interfaces.untagged_vlan`\n\nRead-Only:\n\n- `id` (Number)\n- `name` (String)\n- `vid` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/device_power_ports.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_power_ports Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_device_power_ports (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n- `name_regex` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `power_ports` (List of Object) (see [below for nested schema](#nestedatt--power_ports))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--power_ports\"></a>\n### Nested Schema for `power_ports`\n\nRead-Only:\n\n- `allocated_draw` (Number)\n- `description` (String)\n- `device_id` (Number)\n- `id` (Number)\n- `maximum_draw` (Number)\n- `module_id` (Number)\n- `name` (String)\n- `tag_ids` (List of Number)\n- `type` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/device_render_config.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_render_config Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  Render the configuration template assigned to a device using the device's config context.\n---\n\n# netbox_device_render_config (Data Source)\n\nRender the configuration template assigned to a device using the device's config context.\n\n## Example Usage\n\n```terraform\n# Get the rendered configuration for a device\ndata \"netbox_device_render_config\" \"server_config\" {\n  device_id = 60\n}\n\n# Use the rendered configuration\noutput \"rendered_config\" {\n  value = data.netbox_device_render_config.server_config.content\n}\n\noutput \"template_used\" {\n  value = data.netbox_device_render_config.server_config.config_template_name\n}\n\n# Example: Write the config to a file using local_file resource\n# resource \"local_file\" \"kickstart\" {\n#   content  = data.netbox_device_render_config.server_config.content\n#   filename = \"${path.module}/kickstart.cfg\"\n# }\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number) The ID of the device to render configuration for.\n\n### Read-Only\n\n- `config_template_id` (Number) The ID of the config template that was used for rendering.\n- `config_template_name` (String) The name of the config template that was used for rendering.\n- `content` (String) The rendered configuration content.\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/device_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_role Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_device_role (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_device_role\" \"core_sw\" {\n  name = \"core-sw\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Read-Only\n\n- `color_hex` (String)\n- `id` (String) The ID of this resource.\n- `slug` (String)\n- `tags` (Set of String)\n\n\n"
  },
  {
    "path": "docs/data-sources/device_type.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_type Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_device_type (Data Source)\n\n\n\n## Example Usage\n\n```terraform\n# Get device type by model name\ndata \"netbox_device_type\" \"ex1\" {\n  model = \"7210 SAS-Sx 10/100GE\"\n}\n\n# Get device type by slug\ndata \"netbox_device_type\" \"ex2\" {\n  slug = \"7210-sas-sx-10-100GE\"\n}\n\n# Get device type by manufacturer and part number information\ndata \"netbox_device_type\" \"ex3\" {\n  manufacturer = \"Nokia\"\n  part_number  = \"3HE11597AARB01\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `manufacturer` (String)\n- `model` (String)\n- `part_number` (String)\n- `slug` (String)\n- `subdevice_role` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `is_full_depth` (Boolean)\n- `manufacturer_id` (Number)\n- `u_height` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/devices.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_devices Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_devices (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n- `name_regex` (String)\n\n### Read-Only\n\n- `devices` (List of Object) (see [below for nested schema](#nestedatt--devices))\n- `id` (String) The ID of this resource.\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--devices\"></a>\n### Nested Schema for `devices`\n\nRead-Only:\n\n- `asset_tag` (String)\n- `cluster_id` (Number)\n- `comments` (String)\n- `config_context` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `device_id` (Number)\n- `device_type_id` (Number)\n- `local_context_data` (String)\n- `location_id` (Number)\n- `manufacturer_id` (Number)\n- `model` (String)\n- `name` (String)\n- `oob_ip` (String)\n- `platform_id` (Number)\n- `primary_ipv4` (String)\n- `primary_ipv6` (String)\n- `rack_face` (String)\n- `rack_id` (Number)\n- `rack_position` (Number)\n- `role_id` (Number)\n- `serial` (String)\n- `site_id` (Number)\n- `status` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/interfaces.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_interfaces Data Source - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  \n---\n\n# netbox_interfaces (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_interfaces\" \"myvm_eth0\" {\n  name_regex = \"eth0\"\n  filter {\n    name  = \"name\"\n    value = \"myvm\"\n  }\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) The limit of objects to return from the API lookup. Defaults to `0`.\n- `name_regex` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `interfaces` (List of Object) (see [below for nested schema](#nestedatt--interfaces))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--interfaces\"></a>\n### Nested Schema for `interfaces`\n\nRead-Only:\n\n- `description` (String)\n- `enabled` (Boolean)\n- `id` (Number)\n- `mac_address` (String)\n- `mode` (Map of String)\n- `mtu` (Number)\n- `name` (String)\n- `tag_ids` (List of Number)\n- `tagged_vlans` (List of Object) (see [below for nested schema](#nestedobjatt--interfaces--tagged_vlans))\n- `untagged_vlan` (List of Object) (see [below for nested schema](#nestedobjatt--interfaces--untagged_vlan))\n- `vm_id` (Number)\n\n<a id=\"nestedobjatt--interfaces--tagged_vlans\"></a>\n### Nested Schema for `interfaces.tagged_vlans`\n\nRead-Only:\n\n- `id` (Number)\n- `name` (String)\n- `vid` (Number)\n\n\n<a id=\"nestedobjatt--interfaces--untagged_vlan\"></a>\n### Nested Schema for `interfaces.untagged_vlan`\n\nRead-Only:\n\n- `id` (Number)\n- `name` (String)\n- `vid` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/ip_address.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_ip_address Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_ip_address (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_ip_address\" \"ip_address\" {\n  id = 1001\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Read-Only\n\n- `address_family` (String)\n- `created` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `dns_name` (String)\n- `id` (Number) The ID of this resource.\n- `ip_address` (String)\n- `last_updated` (String)\n- `role` (String)\n- `status` (String)\n- `tags` (List of Object) (see [below for nested schema](#nestedatt--tags))\n- `tenant` (List of Object) (see [below for nested schema](#nestedatt--tenant))\n\n<a id=\"nestedatt--tags\"></a>\n### Nested Schema for `tags`\n\nRead-Only:\n\n- `display` (String)\n- `id` (Number)\n- `name` (String)\n- `slug` (String)\n\n\n<a id=\"nestedatt--tenant\"></a>\n### Nested Schema for `tenant`\n\nRead-Only:\n\n- `id` (Number)\n- `name` (String)\n- `slug` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/ip_addresses.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_ip_addresses Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_ip_addresses (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `ip_addresses` (List of Object) (see [below for nested schema](#nestedatt--ip_addresses))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--ip_addresses\"></a>\n### Nested Schema for `ip_addresses`\n\nRead-Only:\n\n- `address_family` (String)\n- `created` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `dns_name` (String)\n- `id` (Number)\n- `ip_address` (String)\n- `last_updated` (String)\n- `role` (String)\n- `status` (String)\n- `tags` (List of Object) (see [below for nested schema](#nestedobjatt--ip_addresses--tags))\n- `tenant` (List of Object) (see [below for nested schema](#nestedobjatt--ip_addresses--tenant))\n\n<a id=\"nestedobjatt--ip_addresses--tags\"></a>\n### Nested Schema for `ip_addresses.tags`\n\nRead-Only:\n\n- `display` (String)\n- `id` (Number)\n- `name` (String)\n- `slug` (String)\n\n\n<a id=\"nestedobjatt--ip_addresses--tenant\"></a>\n### Nested Schema for `ip_addresses.tenant`\n\nRead-Only:\n\n- `id` (Number)\n- `name` (String)\n- `slug` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/ip_range.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_ip_range Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_ip_range (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_ip_range\" \"cust_a_prod\" {\n  contains = \"10.0.0.1/24\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `contains` (String) At least one of `contains`, `family`, `vrf_id`, `tenant_id`, `status`, `role_id`, `description` or `tag` must be given.\n- `description` (String) Description to include in the data source filter. At least one of `contains`, `family`, `vrf_id`, `tenant_id`, `status`, `role_id`, `description` or `tag` must be given.\n- `family` (Number) The IP family of the IP range. One of 4 or 6. At least one of `contains`, `family`, `vrf_id`, `tenant_id`, `status`, `role_id`, `description` or `tag` must be given.\n- `role_id` (Number) At least one of `contains`, `family`, `vrf_id`, `tenant_id`, `status`, `role_id`, `description` or `tag` must be given.\n- `status` (String) At least one of `contains`, `family`, `vrf_id`, `tenant_id`, `status`, `role_id`, `description` or `tag` must be given.\n- `tag` (String) Tag to include in the data source filter (must match the tag's slug). At least one of `contains`, `family`, `vrf_id`, `tenant_id`, `status`, `role_id`, `description` or `tag` must be given.\n- `tag__n` (String) Tag to exclude from the data source filter (must match the tag's slug).\nRefer to [Netbox's documentation](https://netboxlabs.com/docs/netbox/reference/filtering/#lookup-expressions)\nfor more information on available lookup expressions.\n- `tenant_id` (Number) At least one of `contains`, `family`, `vrf_id`, `tenant_id`, `status`, `role_id`, `description` or `tag` must be given.\n- `vrf_id` (Number) At least one of `contains`, `family`, `vrf_id`, `tenant_id`, `status`, `role_id`, `description` or `tag` must be given.\n\n### Read-Only\n\n- `end_address` (String)\n- `id` (Number) The ID of this resource.\n- `start_address` (String)\n- `tags` (Set of String)\n\n\n"
  },
  {
    "path": "docs/data-sources/ip_ranges.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_ip_ranges Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_ip_ranges (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `ip_ranges` (List of Object) (see [below for nested schema](#nestedatt--ip_ranges))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--ip_ranges\"></a>\n### Nested Schema for `ip_ranges`\n\nRead-Only:\n\n- `address_family` (String)\n- `created` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `end_address` (String)\n- `id` (Number)\n- `last_updated` (String)\n- `role` (String)\n- `start_address` (String)\n- `status` (String)\n- `tags` (List of Object) (see [below for nested schema](#nestedobjatt--ip_ranges--tags))\n- `tenant` (List of Object) (see [below for nested schema](#nestedobjatt--ip_ranges--tenant))\n\n<a id=\"nestedobjatt--ip_ranges--tags\"></a>\n### Nested Schema for `ip_ranges.tags`\n\nRead-Only:\n\n- `display` (String)\n- `id` (Number)\n- `name` (String)\n- `slug` (String)\n\n\n<a id=\"nestedobjatt--ip_ranges--tenant\"></a>\n### Nested Schema for `ip_ranges.tenant`\n\nRead-Only:\n\n- `id` (Number)\n- `name` (String)\n- `slug` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/ipam_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_ipam_role Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_ipam_role (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Read-Only\n\n- `description` (String)\n- `id` (String) The ID of this resource.\n- `slug` (String)\n- `weight` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/location.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_location Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_location (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `name` (String)\n- `parent_id` (Number)\n- `site_id` (Number)\n- `slug` (String)\n\n### Read-Only\n\n- `description` (String)\n- `id` (String) The ID of this resource.\n- `status` (String)\n- `tenant_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/locations.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_locations Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_locations (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) A list of filter to apply to the API query when requesting locations. (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) The limit of objects to return from the API lookup. Defaults to `0`.\n- `tags` (Set of String) A list of tags to filter on.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `locations` (List of Object) (see [below for nested schema](#nestedatt--locations))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String) The name of the field to filter on. Supported fields are: .\n- `value` (String) The value to pass to the specified filter.\n\n\n<a id=\"nestedatt--locations\"></a>\n### Nested Schema for `locations`\n\nRead-Only:\n\n- `description` (String)\n- `facility` (String)\n- `id` (String)\n- `name` (String)\n- `parent_id` (Number)\n- `site_id` (Number)\n- `slug` (String)\n- `status` (String)\n- `tenant_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/platform.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_platform Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_platform (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_platform\" \"PANOS\" {\n  name = \"PANOS\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `manufacturer_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `slug` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/prefix.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_prefix Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_prefix (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `cidr` (String, Deprecated) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given. Conflicts with `prefix`.\n- `custom_fields` (Map of String) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `description` (String) Description to include in the data source filter. At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `family` (Number) The IP family of the prefix. One of 4 or 6. At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `prefix` (String) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given. Conflicts with `cidr`.\n- `role_id` (Number) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `site_id` (Number) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `status` (String) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `tag` (String) Tag to include in the data source filter (must match the tag's slug). At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `tag__n` (String) Tag to exclude from the data source filter (must match the tag's slug).\nRefer to [Netbox's documentation](https://demo.netbox.dev/static/docs/rest-api/filtering/#lookup-expressions)\nfor more information on available lookup expressions.\n- `tenant_id` (Number) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `vlan_id` (Number) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `vlan_vid` (Number) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n- `vrf_id` (Number) At least one of `description`, `family`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `tenant_id`, `site_id`, `role_id`, `cidr`, `custom_fields`, `tag` or `status` must be given.\n\n### Read-Only\n\n- `id` (Number) The ID of this resource.\n- `location_id` (Number)\n- `region_id` (Number)\n- `site_group_id` (Number)\n- `tags` (Set of String)\n\n\n"
  },
  {
    "path": "docs/data-sources/prefixes.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_prefixes Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_prefixes (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) A list of filters to apply to the API query when requesting prefixes. (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) The limit of objects to return from the API lookup. Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `prefixes` (List of Object) (see [below for nested schema](#nestedatt--prefixes))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String) The name of the field to filter on. Supported fields are: `prefix`, `contains`, `vlan_vid`, `vrf_id`, `vlan_id`, `status`, `tenant_id`, `site_id`, `description` & `tag`.\n- `value` (String) The value to pass to the specified filter.\n\n\n<a id=\"nestedatt--prefixes\"></a>\n### Nested Schema for `prefixes`\n\nRead-Only:\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `id` (Number)\n- `location_id` (Number)\n- `prefix` (String)\n- `region_id` (Number)\n- `site_group_id` (Number)\n- `site_id` (Number)\n- `status` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `vlan_id` (Number)\n- `vlan_vid` (Number)\n- `vrf_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/rack_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_rack_role Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_rack_role (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Read-Only\n\n- `color_hex` (String)\n- `description` (String)\n- `id` (String) The ID of this resource.\n- `slug` (String)\n- `tags` (Set of String)\n\n\n"
  },
  {
    "path": "docs/data-sources/racks.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_racks Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_racks (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `racks` (List of Object) (see [below for nested schema](#nestedatt--racks))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--racks\"></a>\n### Nested Schema for `racks`\n\nRead-Only:\n\n- `asset_tag` (String)\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `desc_units` (Boolean)\n- `description` (String)\n- `facility_id` (String)\n- `id` (Number)\n- `location_id` (Number)\n- `max_weight` (Number)\n- `mounting_depth` (Number)\n- `name` (String)\n- `outer_depth` (Number)\n- `outer_unit` (String)\n- `outer_width` (Number)\n- `role_id` (Number)\n- `serial` (String)\n- `site_id` (Number)\n- `status` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `type_id` (Number)\n- `u_height` (Number)\n- `weight` (Number)\n- `weight_unit` (String)\n- `width` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/region.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_region Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_region (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n\n### Read-Only\n\n- `description` (String)\n- `id` (Number) The ID of this resource.\n- `name` (String)\n- `parent_region_id` (Number)\n- `slug` (String)\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nOptional:\n\n- `name` (String)\n- `slug` (String)\n\nRead-Only:\n\n- `id` (Number) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/rir.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_rir Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs:\n  Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which \"owns\" certain address space.\n---\n\n# netbox_rir (Data Source)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs):\n\n> Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which \"owns\" certain address space.\n\n## Example Usage\n\n```terraform\ndata \"netbox_rir\" \"rir_1\" {\n  name = \"ARIN\"\n}\n\ndata \"netbox_rir\" \"rir_2\" {\n  slug = \"arin\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `name` (String) At least one of `name` or `slug` must be given.\n- `slug` (String) At least one of `name` or `slug` must be given.\n\n### Read-Only\n\n- `description` (String)\n- `id` (Number) The ID of this resource.\n- `is_private` (Boolean)\n\n\n"
  },
  {
    "path": "docs/data-sources/route_target.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_route_target Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_route_target (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `tags` (Set of String)\n\n### Read-Only\n\n- `description` (String)\n- `id` (String) The ID of this resource.\n- `tenant_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/site.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_site Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_site (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_site\" \"get_by_name\" {\n  name = \"Example Site 1\"\n}\n\ndata \"netbox_site\" \"get_by_slug\" {\n  slug = \"example-site-1\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `facility` (String)\n- `name` (String)\n- `slug` (String)\n\n### Read-Only\n\n- `asn_ids` (Set of Number)\n- `comments` (String)\n- `description` (String)\n- `group_id` (Number)\n- `id` (String) The ID of this resource.\n- `physical_address` (String)\n- `region_id` (Number)\n- `site_id` (Number)\n- `status` (String)\n- `tenant_id` (Number)\n- `time_zone` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/site_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_site_group Data Source - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  \n---\n\n# netbox_site_group (Data Source)\n\n\n\n## Example Usage\n\n```terraform\n// Assumes the corresponding site groups exist\ndata \"netbox_site_group\" \"get_by_name\" {\n  name = \"example-sitegroup-1\"\n}\n\ndata \"netbox_site_group\" \"get_by_slug\" {\n  slug = \"sitegrp\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `name` (String) At least one of `name` or `slug` must be given.\n- `slug` (String) At least one of `name` or `slug` must be given.\n\n### Read-Only\n\n- `description` (String)\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/tag.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_tag Data Source - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  \n---\n\n# netbox_tag (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_tag\" \"dmz\" {\n  name = \"DMZ\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `slug` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/tags.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_tags Data Source - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  \n---\n\n# netbox_tags (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_tags\" \"all_tags\" {\n}\n\ndata \"netbox_tags\" \"ansible_tags\" {\n  filter {\n    name  = \"name__isw\"\n    value = \"ansible_\"\n  }\n}\n\ndata \"netbox_tags\" \"not_ansible_tags\" {\n  filter {\n    name  = \"name__nisw\"\n    value = \"ansible_\"\n  }\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags` (List of Object) (see [below for nested schema](#nestedatt--tags))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--tags\"></a>\n### Nested Schema for `tags`\n\nRead-Only:\n\n- `color` (String)\n- `description` (String)\n- `name` (String)\n- `slug` (String)\n- `tag_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/tenant.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_tenant Data Source - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  \n---\n\n# netbox_tenant (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_tenant\" \"customer_a\" {\n  name = \"Customer A\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `description` (String)\n- `name` (String) At least one of `name` or `slug` must be given.\n- `slug` (String) At least one of `name` or `slug` must be given.\n\n### Read-Only\n\n- `group_id` (Number)\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/tenant_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_tenant_group Data Source - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  \n---\n\n# netbox_tenant_group (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Read-Only\n\n- `description` (String)\n- `id` (String) The ID of this resource.\n- `parent_id` (Number)\n- `slug` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/tenants.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_tenants Data Source - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  \n---\n\n# netbox_tenants (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tenants` (List of Object) (see [below for nested schema](#nestedatt--tenants))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--tenants\"></a>\n### Nested Schema for `tenants`\n\nRead-Only:\n\n- `circuit_count` (Number)\n- `cluster_count` (Number)\n- `comments` (String)\n- `created` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `device_count` (Number)\n- `id` (Number)\n- `ip_address_count` (Number)\n- `last_updated` (String)\n- `name` (String)\n- `prefix_count` (Number)\n- `rack_count` (Number)\n- `site_count` (Number)\n- `slug` (String)\n- `tenant_group` (List of Object) (see [below for nested schema](#nestedobjatt--tenants--tenant_group))\n- `vlan_count` (Number)\n- `vm_count` (Number)\n- `vrf_count` (Number)\n\n<a id=\"nestedobjatt--tenants--tenant_group\"></a>\n### Nested Schema for `tenants.tenant_group`\n\nRead-Only:\n\n- `id` (Number)\n- `name` (String)\n- `slug` (String)\n- `tenant_count` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/virtual_disk.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_virtual_disk Data Source - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  \n---\n\n# netbox_virtual_disk (Data Source)\n\n\n\n## Example Usage\n\n```terraform\n# Filter by name\ndata \"netbox_virtual_disk\" \"disk_by_name\" {\n  filter {\n    name  = \"name\"\n    value = \"disk1\"\n  }\n}\n\n# Filter by tag\ndata \"netbox_virtual_disk\" \"disk_by_tag\" {\n  filter {\n    name  = \"tag\"\n    value = \"production\"\n  }\n}\n\n# Multiple filters\ndata \"netbox_virtual_disk\" \"disk_filtered\" {\n  filter {\n    name  = \"name\"\n    value = \"disk1\"\n  }\n  filter {\n    name  = \"tag\"\n    value = \"production\"\n  }\n}\n\n# Filter with name regex\ndata \"netbox_virtual_disk\" \"disk_regex\" {\n  name_regex = \"^disk[0-9]+\"\n  limit      = 10\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block List) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n- `name_regex` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `virtual_disks` (List of Object) (see [below for nested schema](#nestedatt--virtual_disks))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--virtual_disks\"></a>\n### Nested Schema for `virtual_disks`\n\nRead-Only:\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `id` (Number)\n- `name` (String)\n- `size_mb` (Number)\n- `tags` (List of String)\n- `virtual_machine_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/virtual_machines.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_virtual_machines Data Source - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  \n---\n\n# netbox_virtual_machines (Data Source)\n\n\n\n## Example Usage\n\n```terraform\n// Assumes vmw-cluster-01 exists as a cluster in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\ndata \"netbox_virtual_machines\" \"base_vm\" {\n  name_regex = \"myvm-1\"\n  filter {\n    name  = \"cluster_id\"\n    value = data.netbox_cluster.vmw_cluster_01.id\n  }\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n- `name_regex` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `vms` (List of Object) (see [below for nested schema](#nestedatt--vms))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--vms\"></a>\n### Nested Schema for `vms`\n\nRead-Only:\n\n- `cluster_id` (Number)\n- `comments` (String)\n- `config_context` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `device_id` (Number)\n- `device_name` (String)\n- `disk_size_mb` (Number)\n- `local_context_data` (String)\n- `memory_mb` (Number)\n- `name` (String)\n- `platform_id` (Number)\n- `platform_name` (String)\n- `platform_slug` (String)\n- `primary_ip` (String)\n- `primary_ip4` (String)\n- `primary_ip6` (String)\n- `role_id` (Number)\n- `site_id` (Number)\n- `status` (String)\n- `tag_ids` (List of Number)\n- `tenant_id` (Number)\n- `vcpus` (Number)\n- `vm_id` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/vlan.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vlan Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_vlan (Data Source)\n\n\n\n## Example Usage\n\n```terraform\n# Get VLAN by name\ndata \"netbox_vlan\" \"vlan1\" {\n  name = \"vlan-1\"\n}\n\n# Get VLAN by VID and IPAM role ID\ndata \"netbox_vlan\" \"vlan2\" {\n  vid  = 1234\n  role = netbox_ipam_role.example.id\n}\n\n# Get VLAN by name and tenant ID\ndata \"netbox_vlan\" \"vlan3\" {\n  name   = \"vlan-3\"\n  tenant = netbox_tenant.example.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `group_id` (Number)\n- `name` (String)\n- `role` (Number)\n- `tenant` (Number)\n- `vid` (Number)\n\n### Read-Only\n\n- `description` (String)\n- `id` (String) The ID of this resource.\n- `site` (Number)\n- `status` (String)\n\n\n"
  },
  {
    "path": "docs/data-sources/vlan_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vlan_group Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_vlan_group (Data Source)\n\n\n\n## Example Usage\n\n```terraform\n# Get VLAN group by name\ndata \"netbox_vlan_group\" \"example1\" {\n  name = \"example1\"\n}\n\n# Get VLAN group by stub\ndata \"netbox_vlan_group\" \"example2\" {\n  slug = \"example2\"\n}\n\n# Get VLAN group by name and scope_type/id\ndata \"netbox_vlan_group\" \"example3\" {\n  name       = \"example\"\n  scope_type = \"dcim.site\"\n  scope_id   = netbox_site.example.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `id` (String) At least one of `id`, `name`, `slug` or `scope_type` must be given.\n- `name` (String) At least one of `id`, `name`, `slug` or `scope_type` must be given.\n- `scope_id` (String) Required when `scope_type` is set.\n- `scope_type` (String) Valid values are `dcim.location`, `dcim.site`, `dcim.sitegroup`, `dcim.region`, `dcim.rack`, `virtualization.cluster` and `virtualization.clustergroup`. At least one of `id`, `name`, `slug` or `scope_type` must be given.\n- `slug` (String) At least one of `id`, `name`, `slug` or `scope_type` must be given.\n\n### Read-Only\n\n- `description` (String)\n- `vlan_count` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/vlan_groups.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vlan_groups Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_vlan_groups (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `vlan_groups` (List of Object) (see [below for nested schema](#nestedatt--vlan_groups))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--vlan_groups\"></a>\n### Nested Schema for `vlan_groups`\n\nRead-Only:\n\n- `description` (String)\n- `id` (Number)\n- `name` (String)\n- `ranges` (List of Object) (see [below for nested schema](#nestedobjatt--vlan_groups--ranges))\n- `slug` (String)\n- `tag_ids` (List of Number)\n- `used` (Number)\n\n<a id=\"nestedobjatt--vlan_groups--ranges\"></a>\n### Nested Schema for `vlan_groups.ranges`\n\nRead-Only:\n\n- `end` (Number)\n- `start` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/vlans.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vlans Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_vlans (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `vlans` (List of Object) (see [below for nested schema](#nestedatt--vlans))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--vlans\"></a>\n### Nested Schema for `vlans`\n\nRead-Only:\n\n- `description` (String)\n- `group_id` (Number)\n- `id` (Number)\n- `name` (String)\n- `role` (Number)\n- `site` (Number)\n- `status` (String)\n- `tag_ids` (List of Number)\n- `tenant` (Number)\n- `vid` (Number)\n\n\n"
  },
  {
    "path": "docs/data-sources/vrf.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vrf Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_vrf (Data Source)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_vrf\" \"cust_a_prod\" {\n  name = \"cust-a-prod\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/data-sources/vrfs.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vrfs Data Source - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_vrfs (Data Source)\n\n\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))\n- `limit` (Number) Defaults to `0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `vrfs` (List of Object) (see [below for nested schema](#nestedatt--vrfs))\n\n<a id=\"nestedblock--filter\"></a>\n### Nested Schema for `filter`\n\nRequired:\n\n- `name` (String)\n- `value` (String)\n\n\n<a id=\"nestedatt--vrfs\"></a>\n### Nested Schema for `vrfs`\n\nRead-Only:\n\n- `description` (String)\n- `id` (Number)\n- `name` (String)\n- `rd` (String)\n- `tenant` (Number)\n\n\n"
  },
  {
    "path": "docs/index.md",
    "content": "---\nlayout: \"\"\npage_title: \"Provider: Netbox\"\ndescription: |-\n  The netbox provider provides resources and data sources to interact with Netbox.\n---\n\n# Netbox Provider\n\nThe Terraform Netbox provider is a plugin for Terraform that allows for the full lifecycle management of [Netbox](https://netboxlabs.com/docs/netbox/) resources.\n\nUse the navigation to the left to read about the available resources.\n\n## Supported Netbox versions\nNetbox often makes breaking API changes even in non-major releases. Check the table below to see which version this provider is compatible with your Netbox version. It is generally recommended to use the provider version matching your Netbox version.\n\n| Netbox version  | Provider version |\n| --------------- | ---------------- |\n| v4.3.0 - 4.4.10 | v5.0.0 and up    |\n| v4.2.2 - 4.2.9  | v4.0.0 - 4.3.1   |\n| v4.1.0 - 4.1.11 | v3.10.0 - 3.11.1 |\n| v4.0.0 - 4.0.11 | v3.9.0 - 3.9.2   |\n| v3.7.0 - 3.7.8  | v3.8.0 - 3.8.9   |\n| v3.6.0 - 3.6.9  | v3.7.0 - 3.7.7   |\n| v3.5.1 - 3.5.9  | v3.6.x           |\n| v3.4.3 - 3.4.10 | v3.5.x           |\n| v3.3.0 - 3.4.2  | v3.0.x - 3.5.1   |\n| v3.2.0 - 3.2.9  | v2.0.x           |\n| v3.1.9          | v1.6.0 - 1.6.7   |\n| v3.1.3          | v1.1.x - 1.5.2   |\n| v3.0.9          | v1.0.x           |\n| v2.11.12        | v0.3.x           |\n| v2.10.10        | v0.2.x           |\n| v2.9            | v0.1.x           |\n\nAdditionally, since version [1.6.6](https://github.com/e-breuninger/terraform-provider-netbox/commit/0b0b2fffa54d4ab2e5f1677e948b01e56ba211c8), each version of the provider has a built-in list of all Netbox versions it supports at release time. Upon initialization, the provider will probe your Netbox version and include a (non-blocking) warning if the used Netbox version is not supported.\n\n## Configuration\nYou must configure the provider with proper credentials before you can use it. You can configure the provider via attributes in the provider block or via environment variables. See [Schema](#schema) for all configuration options\n\n## Example Usage\n\n```terraform\nterraform {\n  required_providers {\n    netbox = {\n      source  = \"e-breuninger/netbox\"\n      version = \"~> 3.2.1\"\n    }\n  }\n}\n\n# example provider configuration for https://demo.netbox.dev\nprovider \"netbox\" {\n  server_url = \"https://demo.netbox.dev\"\n  api_token  = \"<your api key>\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `api_token` (String) Netbox API authentication token. Supports both v1 tokens (`Authorization: Token <key>`) and v2 tokens (`Authorization: Bearer nbt_<key>.<token>`). V2 tokens are auto-detected by their `nbt_` prefix. Can be set via the `NETBOX_API_TOKEN` environment variable.\n- `server_url` (String) Location of Netbox server including scheme (http or https) and optional port. Can be set via the `NETBOX_SERVER_URL` environment variable.\n\n### Optional\n\n- `allow_insecure_https` (Boolean) Flag to set whether to allow https with invalid certificates. Can be set via the `NETBOX_ALLOW_INSECURE_HTTPS` environment variable. Defaults to `false`.\n- `ca_cert_file` (String) Path to a PEM-encoded CA certificate for verifying the Netbox server certificate. Can be set via the `NETBOX_CA_CERT_FILE` environment variable.\n- `default_tags` (Set of String) Tags to add to every resource managed by this provider.\n- `headers` (Map of String) Set these header on all requests to Netbox. Can be set via the `NETBOX_HEADERS` environment variable.\n- `request_timeout` (Number) Netbox API HTTP request timeout in seconds. Can be set via the `NETBOX_REQUEST_TIMEOUT` environment variable.\n- `skip_version_check` (Boolean) If true, do not try to determine the running Netbox version at provider startup. Disables warnings about possibly unsupported Netbox version. Also useful for local testing on terraform plans. Can be set via the `NETBOX_SKIP_VERSION_CHECK` environment variable. Defaults to `false`.\n- `strip_trailing_slashes_from_url` (Boolean) If true, strip trailing slashes from the `server_url` parameter and print a warning when doing so. Note that using trailing slashes in the `server_url` parameter will usually lead to errors. Can be set via the `NETBOX_STRIP_TRAILING_SLASHES_FROM_URL` environment variable. Defaults to `true`.\n"
  },
  {
    "path": "docs/resources/aggregate.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_aggregate Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#aggregates:\n  NetBox allows us to specify the portions of IP space that are interesting to us by defining aggregates. Typically, an aggregate will correspond to either an allocation of public (globally routable) IP space granted by a regional authority, or a private (internally-routable) designation.\n---\n\n# netbox_aggregate (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#aggregates):\n\n> NetBox allows us to specify the portions of IP space that are interesting to us by defining aggregates. Typically, an aggregate will correspond to either an allocation of public (globally routable) IP space granted by a regional authority, or a private (internally-routable) designation.\n\n## Example Usage\n\n```terraform\nresource \"netbox_rir\" \"test\" {\n  name = \"testrir\"\n}\nresource \"netbox_aggregate\" \"test\" {\n  prefix      = \"1.1.1.0/25\"\n  description = \"my description\"\n  rir_id      = netbox_rir.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `prefix` (String)\n\n### Optional\n\n- `description` (String)\n- `rir_id` (Number)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/asn.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_asn Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#asn:\n  > ASN is short for Autonomous System Number. This identifier is used in the BGP protocol to identify which \"autonomous system\" a particular prefix is originating and transiting through.\n  >\n  > The AS number model within NetBox allows you to model some of this real-world relationship.\n---\n\n# netbox_asn (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#asn):\n> ASN is short for Autonomous System Number. This identifier is used in the BGP protocol to identify which \"autonomous system\" a particular prefix is originating and transiting through.\n>\n> The AS number model within NetBox allows you to model some of this real-world relationship.\n\n## Example Usage\n\n```terraform\nresource \"netbox_rir\" \"test\" {\n  name = \"testrir\"\n}\n\nresource \"netbox_asn\" \"test\" {\n  asn         = 1337\n  rir_id      = netbox_rir.test.id\n  description = \"test\"\n  comments    = \"test\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `asn` (Number) Value for the AS Number record.\n- `rir_id` (Number) ID for the RIR for the AS Number record.\n\n### Optional\n\n- `comments` (String) Comments field for the AS Number record.\n- `description` (String) Description field for the AS Number record.\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/available_ip_address.md",
    "content": "---\npage_title: \"netbox_available_ip_address Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  Per the docs https://netbox.readthedocs.io/en/stable/models/ipam/ipaddress/:\n  An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.\n  Like a prefix, an IP address can optionally be assigned to a VRF (otherwise, it will appear in the \"global\" table). IP addresses are automatically arranged under parent prefixes within their respective VRFs according to the IP hierarchya.\n  Each IP address can also be assigned an operational status and a functional role. Statuses are hard-coded in NetBox and include the following:\n  * Active\n  * Reserved\n  * Deprecated\n  * DHCP\n  * SLAAC (IPv6 Stateless Address Autoconfiguration)\n  This resource will retrieve the next available IP address from a given prefix or IP range (specified by ID)\n---\n\n# netbox_available_ip_address (Resource)\n\nPer [the docs](https://netbox.readthedocs.io/en/stable/models/ipam/ipaddress/):\n\n> An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.\n> Like a prefix, an IP address can optionally be assigned to a VRF (otherwise, it will appear in the \"global\" table). IP addresses are automatically arranged under parent prefixes within their respective VRFs according to the IP hierarchya.\n>\n> Each IP address can also be assigned an operational status and a functional role. Statuses are hard-coded in NetBox and include the following:\n> * Active\n> * Reserved\n> * Deprecated\n> * DHCP\n> * SLAAC (IPv6 Stateless Address Autoconfiguration)\n\nThis resource will retrieve the next available IP address from a given prefix or IP range (specified by ID)\n\n## Example Usage\n### Creating an IP in a prefix\n```terraform\ndata \"netbox_prefix\" \"test\" {\n  cidr = \"10.0.0.0/24\"\n}\n\nresource \"netbox_available_ip_address\" \"test\" {\n  prefix_id = data.netbox_prefix.test.id\n}\n```\n\n### Creating an IP in an IP range\n```terraform\ndata \"netbox_ip_range\" \"test\" {\n  start_address = \"10.0.0.1/24\"\n  end_address   = \"10.0.0.50/24\"\n}\n\nresource \"netbox_available_ip_address\" \"test\" {\n  ip_range_id = data.netbox_ip_range.test.id\n}\n```\n\n### Marking an IP active and assigning to interface\n```terraform\n// Assumes Netbox already has a VM whos name matches 'dc-west-myvm-20'\ndata \"netbox_virtual_machine\" \"myvm\" {\n  name_regex = \"dc-west-myvm-20\"\n}\n\ndata \"netbox_prefix\" \"test\" {\n  cidr = \"10.0.0.0/24\"\n}\n\nresource \"netbox_interface\" \"myvm-eth0\" {\n  name               = \"eth0\"\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n\nresource \"netbox_available_ip_address\" \"myvm-ip\" {\n  prefix_id    = data.netbox_prefix.test.id\n  status       = \"active\"\n  interface_id = netbox_interface.myvm-eth0.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `device_interface_id` (Number) Conflicts with `interface_id` and `virtual_machine_interface_id`.\n- `dns_name` (String)\n- `interface_id` (Number) Required when `object_type` is set.\n- `ip_range_id` (Number) Exactly one of `prefix_id` or `ip_range_id` must be given.\n- `object_type` (String) Valid values are `virtualization.vminterface` and `dcim.interface`. Required when `interface_id` is set.\n- `prefix_id` (Number) Exactly one of `prefix_id` or `ip_range_id` must be given.\n- `role` (String) Valid values are `loopback`, `secondary`, `anycast`, `vip`, `vrrp`, `hsrp`, `glbp` and `carp`.\n- `status` (String) Valid values are `active`, `reserved`, `deprecated`, `dhcp` and `slaac`. Defaults to `active`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `virtual_machine_interface_id` (Number) Conflicts with `interface_id` and `device_interface_id`.\n- `vrf_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `ip_address` (String)\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/available_prefix.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_available_prefix Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  \n---\n\n# netbox_available_prefix (Resource)\n\n\n\n## Example Usage\n\n```terraform\ndata \"netbox_prefix\" \"test\" {\n  cidr = \"10.0.0.0/24\"\n}\n\nresource \"netbox_available_prefix\" \"test\" {\n  parent_prefix_id = data.netbox_prefix.test.id\n  prefix_length    = 25\n  status           = \"active\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `parent_prefix_id` (Number)\n- `prefix_length` (Number)\n- `status` (String) Valid values are `active`, `container`, `reserved` and `deprecated`.\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `is_pool` (Boolean)\n- `location_id` (Number) Conflicts with `site_id`, `site_group_id` and `region_id`.\n- `mark_utilized` (Boolean)\n- `region_id` (Number) Conflicts with `location_id`, `site_id` and `site_group_id`.\n- `role_id` (Number)\n- `site_group_id` (Number) Conflicts with `location_id`, `site_id` and `region_id`.\n- `site_id` (Number) Conflicts with `location_id`, `site_group_id` and `region_id`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `vlan_id` (Number)\n- `vrf_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `prefix` (String)\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/available_vlan.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_available_vlan Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  Per the docs https://netbox.readthedocs.io/en/stable/models/ipam/vlan/:\n  A VLAN represents an isolated Layer 2 domain identified by a numeric ID (1–4094). VLANs may be assigned to specific sites or marked as global.\n  Optionally, they can be organized within VLAN groups to define scope and enforce uniqueness.\n  Each VLAN can also be assigned an operational status and a functional role. Statuses are hard-coded in NetBox and include the following:\n  * Active\n  * Reserved\n  * Deprecated\n  This resource will retrieve the next available VLAN ID from a given VLAN group (specified by ID).\n---\n\n# netbox_available_vlan (Resource)\n\nPer [the docs](https://netbox.readthedocs.io/en/stable/models/ipam/vlan/):\n\n> A VLAN represents an isolated Layer 2 domain identified by a numeric ID (1–4094). VLANs may be assigned to specific sites or marked as global.\n> Optionally, they can be organized within VLAN groups to define scope and enforce uniqueness.\n>\n> Each VLAN can also be assigned an operational status and a functional role. Statuses are hard-coded in NetBox and include the following:\n> * Active\n> * Reserved\n> * Deprecated\n\nThis resource will retrieve the next available VLAN ID from a given VLAN group (specified by ID).\n\n\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `group_id` (Number)\n- `role_id` (Number)\n- `site_id` (Number)\n- `status` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `comments` (String)\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n- `vid` (Number)\n\n\n"
  },
  {
    "path": "docs/resources/cable.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_cable Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/cable/:\n  All connections between device components in NetBox are represented using cables. A cable represents a direct physical connection between two sets of endpoints (A and B), such as a console port and a patch panel port, or between two network interfaces.\n---\n\n# netbox_cable (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/cable/):\n\n> All connections between device components in NetBox are represented using cables. A cable represents a direct physical connection between two sets of endpoints (A and B), such as a console port and a patch panel port, or between two network interfaces.\n\n## Example Usage\n\n```terraform\n// assumes that the referenced console port resources exist\nresource \"netbox_cable\" \"test\" {\n  a_termination {\n    object_type = \"dcim.consoleserverport\"\n    object_id   = netbox_device_console_server_port.kvm1.id\n  }\n  a_termination {\n    object_type = \"dcim.consoleserverport\"\n    object_id   = netbox_device_console_server_port.kvm2.id\n  }\n\n  b_termination {\n    object_type = \"dcim.consoleport\"\n    object_id   = netbox_device_console_port.server1.id\n  }\n  b_termination {\n    object_type = \"dcim.consoleport\"\n    object_id   = netbox_device_console_port.server2.id\n  }\n\n  status      = \"connected\"\n  label       = \"KVM cable\"\n  type        = \"cat8\"\n  color_hex   = \"123456\"\n  length      = 10\n  length_unit = \"m\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `a_termination` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--a_termination))\n- `b_termination` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--b_termination))\n- `status` (String) One of [connected, planned, decommissioning].\n\n### Optional\n\n- `color_hex` (String)\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `label` (String)\n- `length` (Number)\n- `length_unit` (String) One of [km, m, cm, mi, ft, in]. Required when `length` is set.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `type` (String) One of [cat3, cat5, cat5e, cat6, cat6a, cat7, cat7a, cat8, dac-active, dac-passive, mrj21-trunk, coaxial, mmf, mmf-om1, mmf-om2, mmf-om3, mmf-om4, mmf-om5, smf, smf-os1, smf-os2, aoc, power, usb].\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n<a id=\"nestedblock--a_termination\"></a>\n### Nested Schema for `a_termination`\n\nRequired:\n\n- `object_id` (Number)\n- `object_type` (String)\n\n\n<a id=\"nestedblock--b_termination\"></a>\n### Nested Schema for `b_termination`\n\nRequired:\n\n- `object_id` (Number)\n- `object_type` (String)\n\n\n"
  },
  {
    "path": "docs/resources/circuit.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_circuit Resource - terraform-provider-netbox\"\nsubcategory: \"Circuits\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/circuits/#circuits_1:\n  A communications circuit represents a single physical link connecting exactly two endpoints, commonly referred to as its A and Z terminations. A circuit in NetBox may have zero, one, or two terminations defined. It is common to have only one termination defined when you don't necessarily care about the details of the provider side of the circuit, e.g. for Internet access circuits. Both terminations would likely be modeled for circuits which connect one customer site to another.\n  Each circuit is associated with a provider and a user-defined type. For example, you might have Internet access circuits delivered to each site by one provider, and private MPLS circuits delivered by another. Each circuit must be assigned a circuit ID, each of which must be unique per provider.\n---\n\n# netbox_circuit (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuits_1):\n\n> A communications circuit represents a single physical link connecting exactly two endpoints, commonly referred to as its A and Z terminations. A circuit in NetBox may have zero, one, or two terminations defined. It is common to have only one termination defined when you don't necessarily care about the details of the provider side of the circuit, e.g. for Internet access circuits. Both terminations would likely be modeled for circuits which connect one customer site to another.\n>\n> Each circuit is associated with a provider and a user-defined type. For example, you might have Internet access circuits delivered to each site by one provider, and private MPLS circuits delivered by another. Each circuit must be assigned a circuit ID, each of which must be unique per provider.\n\n## Example Usage\n\n```terraform\nresource \"netbox_tenant\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_circuit_provider\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_circuit_type\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_circuit\" \"test\" {\n  cid         = \"test\"\n  status      = \"active\"\n  provider_id = netbox_circuit_provider.test.id\n  type_id     = netbox_circuit_type.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `cid` (String)\n- `provider_id` (Number)\n- `status` (String) Valid values are `planned`, `provisioning`, `active`, `offline`, `deprovisioning` and `decommissioning`.\n- `type_id` (Number)\n\n### Optional\n\n- `description` (String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/circuit_provider.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_circuit_provider Resource - terraform-provider-netbox\"\nsubcategory: \"Circuits\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/circuits/#providers:\n  A circuit provider is any entity which provides some form of connectivity of among sites or organizations within a site. While this obviously includes carriers which offer Internet and private transit service, it might also include Internet exchange (IX) points and even organizations with whom you peer directly. Each circuit within NetBox must be assigned a provider and a circuit ID which is unique to that provider.\n  Each provider may be assigned an autonomous system number (ASN), an account number, and contact information.\n---\n\n# netbox_circuit_provider (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#providers):\n\n> A circuit provider is any entity which provides some form of connectivity of among sites or organizations within a site. While this obviously includes carriers which offer Internet and private transit service, it might also include Internet exchange (IX) points and even organizations with whom you peer directly. Each circuit within NetBox must be assigned a provider and a circuit ID which is unique to that provider.\n>\n> Each provider may be assigned an autonomous system number (ASN), an account number, and contact information.\n\n## Example Usage\n\n```terraform\nresource \"netbox_circuit_provider\" \"test\" {\n  name = \"test\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/circuit_termination.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_circuit_termination Resource - terraform-provider-netbox\"\nsubcategory: \"Circuits\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/circuits/#circuit-terminations:\n  The association of a circuit with a particular site and/or device is modeled separately as a circuit termination. A circuit may have up to two terminations, labeled A and Z. A single-termination circuit can be used when you don't know (or care) about the far end of a circuit (for example, an Internet access circuit which connects to a transit provider). A dual-termination circuit is useful for tracking circuits which connect two sites.\n  Each circuit termination is attached to either a site or to a provider network. Site terminations may optionally be connected via a cable to a specific device interface or port within that site. Each termination must be assigned a port speed, and can optionally be assigned an upstream speed if it differs from the downstream speed (a common scenario with e.g. DOCSIS cable modems). Fields are also available to track cross-connect and patch panel details.\n---\n\n# netbox_circuit_termination (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuit-terminations):\n\n> The association of a circuit with a particular site and/or device is modeled separately as a circuit termination. A circuit may have up to two terminations, labeled A and Z. A single-termination circuit can be used when you don't know (or care) about the far end of a circuit (for example, an Internet access circuit which connects to a transit provider). A dual-termination circuit is useful for tracking circuits which connect two sites.\n>\n> Each circuit termination is attached to either a site or to a provider network. Site terminations may optionally be connected via a cable to a specific device interface or port within that site. Each termination must be assigned a port speed, and can optionally be assigned an upstream speed if it differs from the downstream speed (a common scenario with e.g. DOCSIS cable modems). Fields are also available to track cross-connect and patch panel details.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_circuit_provider\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_circuit_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_circuit\" \"test\" {\n  cid         = \"%[1]s\"\n  status      = \"active\"\n  provider_id = netbox_circuit_provider.test.id\n  type_id     = netbox_circuit_type.test.id\n}\n\nresource \"netbox_circuit_termination\" \"test\" {\n  circuit_id     = netbox_circuit.test.id\n  term_side      = \"A\"\n  site_id        = netbox_site.test.id\n  port_speed     = 100000\n  upstream_speed = 50000\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `circuit_id` (Number)\n- `term_side` (String) Valid values are `A` and `Z`.\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `location_id` (Number) Exactly one of `site_id`, `site_group_id`, `region_id` or `provider_network_id` must be given.\n- `port_speed` (Number)\n- `provider_network_id` (Number) Exactly one of `location_id`, `site_id`, `site_group_id` or `region_id` must be given.\n- `region_id` (Number) Exactly one of `location_id`, `site_id`, `site_group_id` or `provider_network_id` must be given.\n- `site_group_id` (Number) Exactly one of `location_id`, `site_id`, `region_id` or `provider_network_id` must be given.\n- `site_id` (Number) Exactly one of `location_id`, `site_group_id`, `region_id` or `provider_network_id` must be given.\n- `tags` (Set of String)\n- `upstream_speed` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/circuit_type.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_circuit_type Resource - terraform-provider-netbox\"\nsubcategory: \"Circuits\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/circuits/#circuit-types:\n  Circuits are classified by functional type. These types are completely customizable, and are typically used to convey the type of service being delivered over a circuit.\n---\n\n# netbox_circuit_type (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuit-types):\n\n> Circuits are classified by functional type. These types are completely customizable, and are typically used to convey the type of service being delivered over a circuit.\n\n## Example Usage\n\n```terraform\nresource \"netbox_circuit_type\" \"test\" {\n  name = \"test\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/cluster.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_cluster Resource - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  From the official documentation https://netboxlabs.com/docs/netbox/models/virtualization/cluster/:\n  > A cluster is a logical grouping of physical resources within which virtual machines run. Physical devices may be associated with clusters as hosts. This allows users to track on which host(s) a particular virtual machine may reside.\n---\n\n# netbox_cluster (Resource)\n\nFrom the [official documentation](https://netboxlabs.com/docs/netbox/models/virtualization/cluster/):\n> A cluster is a logical grouping of physical resources within which virtual machines run. Physical devices may be associated with clusters as hosts. This allows users to track on which host(s) a particular virtual machine may reside.\n\n## Example Usage\n\n```terraform\n// Assumes the 'dc-west' cluster group already exists\ndata \"netbox_cluster_group\" \"dc_west\" {\n  name = \"dc-west\"\n}\n\nresource \"netbox_cluster_type\" \"vmw_vsphere\" {\n  name = \"VMware vSphere 6\"\n}\n\nresource \"netbox_cluster\" \"vmw_cluster_01\" {\n  cluster_type_id  = netbox_cluster_type.vmw_vsphere.id\n  name             = \"vmw-cluster-01\"\n  cluster_group_id = data.netbox_cluster_group.dc_west.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `cluster_type_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `cluster_group_id` (Number)\n- `comments` (String)\n- `description` (String)\n- `location_id` (Number) Conflicts with `site_id`, `site_group_id` and `region_id`.\n- `region_id` (Number) Conflicts with `location_id`, `site_id` and `site_group_id`.\n- `site_group_id` (Number) Conflicts with `location_id`, `site_id` and `region_id`.\n- `site_id` (Number) Conflicts with `location_id`, `site_group_id` and `region_id`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/cluster_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_cluster_group Resource - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#cluster-groups:\n  Cluster groups may be created for the purpose of organizing clusters. The arrangement of clusters into groups is optional.\n---\n\n# netbox_cluster_group (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#cluster-groups):\n\n> Cluster groups may be created for the purpose of organizing clusters. The arrangement of clusters into groups is optional.\n\n## Example Usage\n\n```terraform\nresource \"netbox_cluster_group\" \"dc_west\" {\n  description = \"West Datacenter Cluster\"\n  name        = \"dc-west\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/cluster_type.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_cluster_type Resource - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#cluster-types:\n  A cluster type represents a technology or mechanism by which a cluster is formed. For example, you might create a cluster type named \"VMware vSphere\" for a locally hosted cluster or \"DigitalOcean NYC3\" for one hosted by a cloud provider.\n---\n\n# netbox_cluster_type (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#cluster-types):\n\n> A cluster type represents a technology or mechanism by which a cluster is formed. For example, you might create a cluster type named \"VMware vSphere\" for a locally hosted cluster or \"DigitalOcean NYC3\" for one hosted by a cloud provider.\n\n## Example Usage\n\n```terraform\nresource \"netbox_cluster_type\" \"vmw_vsphere\" {\n  name = \"VMware vSphere 6\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/config_context.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_config_context Resource - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/extras/configcontext/:\n  Context data is made available to devices and/or virtual machines based on their relationships to other objects in NetBox. For example, context data can be associated only with devices assigned to a particular site, or only to virtual machines in a certain cluster.\n---\n\n# netbox_config_context (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/extras/configcontext/):\n\n> Context data is made available to devices and/or virtual machines based on their relationships to other objects in NetBox. For example, context data can be associated only with devices assigned to a particular site, or only to virtual machines in a certain cluster.\n\n## Example Usage\n\n```terraform\nresource \"netbox_config_context\" \"test\" {\n  name = \"%s\"\n  data = jsonencode({ \"testkey\" = \"testval\" })\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `data` (String)\n- `name` (String)\n\n### Optional\n\n- `cluster_groups` (Set of Number)\n- `cluster_types` (Set of Number)\n- `clusters` (Set of Number)\n- `description` (String)\n- `device_types` (Set of Number)\n- `locations` (Set of Number)\n- `platforms` (Set of Number)\n- `regions` (Set of Number)\n- `roles` (Set of Number)\n- `site_groups` (Set of Number)\n- `sites` (Set of Number)\n- `tags` (Set of String)\n- `tenant_groups` (Set of Number)\n- `tenants` (Set of Number)\n- `weight` (Number) Defaults to `1000`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/config_template.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_config_template Resource - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/extras/configtemplate/:\n  Configuration templates can be used to render device configurations from context data. Templates are written in the Jinja2 language and can be associated with devices roles, platforms, and/or individual devices.\n  Context data is made available to devices and/or virtual machines based on their relationships to other objects in NetBox. For example, context data can be associated only with devices assigned to a particular site, or only to virtual machines in a certain cluster.\n---\n\n# netbox_config_template (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/extras/configtemplate/):\n\n> Configuration templates can be used to render device configurations from context data. Templates are written in the Jinja2 language and can be associated with devices roles, platforms, and/or individual devices.\n\n> Context data is made available to devices and/or virtual machines based on their relationships to other objects in NetBox. For example, context data can be associated only with devices assigned to a particular site, or only to virtual machines in a certain cluster.\n\n## Example Usage\n\n```terraform\nresource \"netbox_config_template\" \"test\" {\n  name               = \"test\"\n  description        = \"test description\"\n  template_code      = \"hostname {{ name }}\"\n  environment_params = jsonencode({ \"name\" = \"my-hostname\" })\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `template_code` (String)\n\n### Optional\n\n- `description` (String)\n- `environment_params` (String) Defaults to `{}`.\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/contact.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_contact Resource - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/contacts/#contacts_1:\n  A contact should represent an individual or permanent point of contact. Each contact must define a name, and may optionally include a title, phone number, email address, and related details.\n  Contacts are reused for assignments, so each unique contact must be created only once and can be assigned to any number of NetBox objects, and there is no limit to the number of assigned contacts an object may have. Most core objects in NetBox can have contacts assigned to them.\n---\n\n# netbox_contact (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contacts_1):\n\n> A contact should represent an individual or permanent point of contact. Each contact must define a name, and may optionally include a title, phone number, email address, and related details.\n>\n> Contacts are reused for assignments, so each unique contact must be created only once and can be assigned to any number of NetBox objects, and there is no limit to the number of assigned contacts an object may have. Most core objects in NetBox can have contacts assigned to them.\n\n## Example Usage\n\n```terraform\nresource \"netbox_contact\" \"test\" {\n  name  = \"John Doe\"\n  email = \"test@example.com\"\n  phone = \"123-123123\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `email` (String)\n- `group_id` (Number)\n- `link` (String)\n- `phone` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/contact_assignment.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_contact_assignment Resource - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/contacts#contactassignments_1:\n  Much like tenancy, contact assignment enables you to track ownership of resources modeled in NetBox.\n---\n\n# netbox_contact_assignment (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/contacts#contactassignments_1):\n\n> Much like tenancy, contact assignment enables you to track ownership of resources modeled in NetBox.\n\n## Example Usage\n\n```terraform\nresource \"netbox_contact\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_contact_role\" \"test\" {\n  name = \"test\"\n}\n\n// Assumes that a device with id 123 exists\nresource \"netbox_contact_assignment\" \"test\" {\n  content_type = \"dcim.device\"\n  object_id    = 123\n  contact_id   = netbox_contact.test.id\n  role_id      = netbox_contact_role.test.id\n  priority     = \"primary\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `contact_id` (Number)\n- `content_type` (String)\n- `object_id` (Number)\n- `role_id` (Number)\n\n### Optional\n\n- `priority` (String) Valid values are `primary`, `secondary`, `tertiary` and `inactive`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/contact_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_contact_group Resource - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/contacts/#contact-groups:\n  Contacts can be grouped arbitrarily into a recursive hierarchy, and a contact can be assigned to a group at any level within the hierarchy.\n---\n\n# netbox_contact_group (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contact-groups):\n\n> Contacts can be grouped arbitrarily into a recursive hierarchy, and a contact can be assigned to a group at any level within the hierarchy.\n\n## Example Usage\n\n```terraform\nresource \"netbox_contact_group\" \"test\" {\n  name = \"test\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `parent_id` (Number)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/contact_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_contact_role Resource - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/contacts/#contactroles:\n  A contact role defines the relationship of a contact to an assigned object. For example, you might define roles for administrative, operational, and emergency contacts\n---\n\n# netbox_contact_role (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contactroles):\n\n> A contact role defines the relationship of a contact to an assigned object. For example, you might define roles for administrative, operational, and emergency contacts\n\n## Example Usage\n\n```terraform\nresource \"netbox_contact_role\" \"test\" {\n  name = \"test\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/custom_field.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_custom_field Resource - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/customization/custom-fields/#custom-fields:\n  Each model in NetBox is represented in the database as a discrete table, and each attribute of a model exists as a column within its table. For example, sites are stored in the dcimsite table, which has columns named name, facility, physicaladdress, and so on. As new attributes are added to objects throughout the development of NetBox, tables are expanded to include new rows.\n  However, some users might want to store additional object attributes that are somewhat esoteric in nature, and that would not make sense to include in the core NetBox database schema. For instance, suppose your organization needs to associate each device with a ticket number correlating it with an internal support system record. This is certainly a legitimate use for NetBox, but it's not a common enough need to warrant including a field for every NetBox installation. Instead, you can create a custom field to hold this data.\n---\n\n# netbox_custom_field (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/customization/custom-fields/#custom-fields):\n\n> Each model in NetBox is represented in the database as a discrete table, and each attribute of a model exists as a column within its table. For example, sites are stored in the dcim_site table, which has columns named name, facility, physical_address, and so on. As new attributes are added to objects throughout the development of NetBox, tables are expanded to include new rows.\n>\n> However, some users might want to store additional object attributes that are somewhat esoteric in nature, and that would not make sense to include in the core NetBox database schema. For instance, suppose your organization needs to associate each device with a ticket number correlating it with an internal support system record. This is certainly a legitimate use for NetBox, but it's not a common enough need to warrant including a field for every NetBox installation. Instead, you can create a custom field to hold this data.\n\n## Example Usage\n\n```terraform\nresource \"netbox_custom_field\" \"test\" {\n  name             = \"test\"\n  type             = \"text\"\n  content_types    = [\"virtualization.vminterface\"]\n  weight           = 100\n  validation_regex = \"^.*$\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `content_types` (Set of String)\n- `name` (String)\n- `type` (String)\n\n### Optional\n\n- `choice_set_id` (Number)\n- `default` (String)\n- `description` (String)\n- `group_name` (String)\n- `label` (String)\n- `required` (Boolean)\n- `validation_maximum` (Number)\n- `validation_minimum` (Number)\n- `validation_regex` (String)\n- `weight` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/custom_field_choice_set.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_custom_field_choice_set Resource - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/extras/customfieldchoiceset/:\n  Single- and multi-selection custom fields must define a set of valid choices from which the user may choose when defining the field value. These choices are defined as sets that may be reused among multiple custom fields.\n  A choice set must define a base choice set and/or a set of arbitrary extra choices.\n---\n\n# netbox_custom_field_choice_set (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/extras/customfieldchoiceset/):\n\nSingle- and multi-selection custom fields must define a set of valid choices from which the user may choose when defining the field value. These choices are defined as sets that may be reused among multiple custom fields.\n\nA choice set must define a base choice set and/or a set of arbitrary extra choices.\n\n## Example Usage\n\n```terraform\nresource \"netbox_custom_field_choice_set\" \"test\" {\n  name        = \"my-custom-field-set\"\n  description = \"Description\"\n  extra_choices = [\n    [\"choice1\", \"label1\"], # label and choice are different\n    [\"choice2\", \"choice2\"] # label and choice are the same\n  ]\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `base_choices` (String) Valid values are `IATA`, `ISO_3166` and `UN_LOCODE`. At least one of `base_choices` or `extra_choices` must be given.\n- `custom_fields` (Map of String)\n- `description` (String)\n- `extra_choices` (List of List of String) This length of the inner lists must be exactly two, where the first value is the value of a choice and the second value is the label of the choice. At least one of `base_choices` or `extra_choices` must be given.\n- `order_alphabetically` (Boolean) experimental. Defaults to `false`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/device.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/devices/#devices:\n  Every piece of hardware which is installed within a site or rack exists in NetBox as a device. Devices are measured in rack units (U) and can be half depth or full depth. A device may have a height of 0U: These devices do not consume vertical rack space and cannot be assigned to a particular rack unit. A common example of a 0U device is a vertically-mounted PDU.\n---\n\n# netbox_device (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#devices):\n\n> Every piece of hardware which is installed within a site or rack exists in NetBox as a device. Devices are measured in rack units (U) and can be half depth or full depth. A device may have a height of 0U: These devices do not consume vertical rack space and cannot be assigned to a particular rack unit. A common example of a 0U device is a vertically-mounted PDU.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name      = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model           = \"test\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n  local_context_data = jsonencode({\n    \"setting_a\" = \"Some Setting\"\n    \"setting_b\" = 42\n  })\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_type_id` (Number)\n- `name` (String)\n- `role_id` (Number)\n- `site_id` (Number)\n\n### Optional\n\n- `asset_tag` (String)\n- `cluster_id` (Number)\n- `comments` (String)\n- `config_template_id` (Number)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `local_context_data` (String) This is best managed through the use of `jsonencode` and a map of settings.\n- `location_id` (Number)\n- `platform_id` (Number)\n- `rack_face` (String) Valid values are `front` and `rear`. Required when `rack_position` is set.\n- `rack_id` (Number)\n- `rack_position` (Number)\n- `serial` (String)\n- `status` (String) Valid values are `offline`, `active`, `planned`, `staged`, `failed`, `inventory` and `decommissioning`. Defaults to `active`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `virtual_chassis_id` (Number) Required when `virtual_chassis_master` and `virtual_chassis_id` is set.\n- `virtual_chassis_master` (Boolean) Required when `virtual_chassis_master` and `virtual_chassis_id` is set.\n- `virtual_chassis_position` (Number)\n- `virtual_chassis_priority` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `primary_ipv4` (Number)\n- `primary_ipv6` (Number)\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_bay.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_bay Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/devicebay/:\n  Device bays represent a space or slot within a device in which a field-replaceable device may be installed. A common example is that of a chassis-based server that holds a number of blades which may contain device components that don't fit the module pattern. Devices in turn hold additional components that become available to the parent device.\n---\n\n# netbox_device_bay (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/devicebay/):\n\n> Device bays represent a space or slot within a device in which a field-replaceable device may be installed. A common example is that of a chassis-based server that holds a number of blades which may contain device components that don't fit the module pattern. Devices in turn hold additional components that become available to the parent device.\n\n## Example Usage\n\n```terraform\nresource \"netbox_tenant\" \"example\" {\n  name = \"example_tenant\"\n}\n\nresource \"netbox_site\" \"example\" {\n  name   = \"example_site\"\n  status = \"active\"\n}\n\nresource \"netbox_manufacturer\" \"example\" {\n  name = \"example_manufacturer\"\n}\n\nresource \"netbox_device_type\" \"example\" {\n  model           = \"example_device_type\"\n  manufacturer_id = netbox_manufacturer.example.id\n  subdevice_role  = \"parent\"\n}\n\nresource \"netbox_device_type\" \"example_installed\" {\n  model           = \"example_device_type_installed\"\n  manufacturer_id = netbox_manufacturer.example.id\n  u_height        = 0\n  subdevice_role  = \"child\"\n}\n\nresource \"netbox_device_role\" \"example\" {\n  name      = \"example_role\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"example\" {\n  name           = \"example_device\"\n  device_type_id = netbox_device_type.example.id\n  tenant_id      = netbox_tenant.example.id\n  role_id        = netbox_device_role.example.id\n  site_id        = netbox_site.example.id\n}\n\nresource \"netbox_device\" \"example_installed\" {\n  name           = \"example_device_installed\"\n  device_type_id = netbox_device_type.example_installed.id\n  tenant_id      = netbox_tenant.example.id\n  role_id        = netbox_device_role.example.id\n  site_id        = netbox_site.example.id\n}\n\nresource \"netbox_device_bay\" \"example\" {\n  device_id           = netbox_device.example.id\n  name                = \"example_device_bay\"\n  label               = \"example_label\"\n  description         = \"example_description\"\n  installed_device_id = netbox_device.example_installed.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `installed_device_id` (Number)\n- `label` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_bay_template.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_bay_template Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/devicebaytemplate/:\n  A template for a device bay that will be created on all instantiations of the parent device type.\n---\n\n# netbox_device_bay_template (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/devicebaytemplate/):\n\n> A template for a device bay that will be created on all instantiations of the parent device type.\n\n## Example Usage\n\n```terraform\nresource \"netbox_manufacturer\" \"example\" {\n  name = \"example_manufacturer\"\n}\n\nresource \"netbox_device_type\" \"example\" {\n  model           = \"example_device_model\"\n  slug            = \"example_device_slug\"\n  part_number     = \"example_part_number\"\n  manufacturer_id = netbox_manufacturer.example.id\n  subdevice_role  = \"parent\"\n}\n\nresource \"netbox_device_bay_template\" \"example\" {\n  name           = \"example_device_bay_template\"\n  device_type_id = netbox_device_type.example.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_type_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `label` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/device_console_port.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_console_port Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/consoleport/:\n  A console port provides connectivity to the physical console of a device. These are typically used for temporary access by someone who is physically near the device, or for remote out-of-band access provided via a networked console server.\n---\n\n# netbox_device_console_port (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/consoleport/):\n\n> A console port provides connectivity to the physical console of a device. These are typically used for temporary access by someone who is physically near the device, or for remote out-of-band access provided via a networked console server.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_console_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"console port\"\n  type           = \"de-9\"\n  speed          = 1200\n  mark_connected = true\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `label` (String)\n- `mark_connected` (Boolean) Defaults to `false`.\n- `module_id` (Number)\n- `speed` (Number) One of [1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200].\n- `tags` (Set of String)\n- `type` (String) One of [de-9, db-25, rj-11, rj-12, rj-45, mini-din-8, usb-a, usb-b, usb-c, usb-mini-a, usb-mini-b, usb-micro-a, usb-micro-b, usb-micro-ab, other].\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_console_server_port.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_console_server_port Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/consoleserverport/:\n  A console server is a device which provides remote access to the local consoles of connected devices. They are typically used to provide remote out-of-band access to network devices, and generally connect to console ports.\n---\n\n# netbox_device_console_server_port (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/consoleserverport/):\n\n> A console server is a device which provides remote access to the local consoles of connected devices. They are typically used to provide remote out-of-band access to network devices, and generally connect to console ports.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_console_server_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"console server port\"\n  type           = \"de-9\"\n  speed          = 1200\n  mark_connected = true\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `label` (String)\n- `mark_connected` (Boolean) Defaults to `false`.\n- `module_id` (Number)\n- `speed` (Number) One of [1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200].\n- `tags` (Set of String)\n- `type` (String) One of [de-9, db-25, rj-11, rj-12, rj-45, mini-din-8, usb-a, usb-b, usb-c, usb-mini-a, usb-mini-b, usb-micro-a, usb-micro-b, usb-micro-ab, other].\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_front_port.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_front_port Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/frontport/:\n  Front ports are pass-through ports which represent physical cable connections that comprise part of a longer path. For example, the ports on the front face of a UTP patch panel would be modeled in NetBox as front ports. Each port is assigned a physical type, and must be mapped to a specific rear port on the same device. A single rear port may be mapped to multiple front ports, using numeric positions to annotate the specific alignment of each.\n---\n\n# netbox_device_front_port (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/frontport/):\n\n> Front ports are pass-through ports which represent physical cable connections that comprise part of a longer path. For example, the ports on the front face of a UTP patch panel would be modeled in NetBox as front ports. Each port is assigned a physical type, and must be mapped to a specific rear port on the same device. A single rear port may be mapped to multiple front ports, using numeric positions to annotate the specific alignment of each.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"rear port 1\"\n  type           = \"8p8c\"\n  positions      = 2\n  mark_connected = true\n}\n\nresource \"netbox_device_front_port\" \"test\" {\n  device_id          = netbox_device.test.id\n  name               = \"front port 1\"\n  type               = \"8p8c\"\n  rear_port_id       = netbox_device_rear_port.test.id\n  rear_port_position = 2\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n- `rear_port_id` (Number)\n- `rear_port_position` (Number)\n- `type` (String) One of [8p8c, 8p6c, 8p4c, 8p2c, 6p6c, 6p4c, 6p2c, 4p4c, 4p2c, gg45, tera-4p, tera-2p, tera-1p, 110-punch, bnc, f, n, mrj21, fc, lc, lc-pc, lc-upc, lc-apc, lsh, lsh-pc, lsh-upc, lsh-apc, mpo, mtrj, sc, sc-pc, sc-upc, sc-apc, st, cs, sn, sma-905, sma-906, urm-p2, urm-p4, urm-p8, splice, other].\n\n### Optional\n\n- `color_hex` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `label` (String)\n- `mark_connected` (Boolean) Defaults to `false`.\n- `module_id` (Number)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_interface.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_interface Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/device/#interface:\n  Interfaces in NetBox represent network interfaces used to exchange data with connected devices. On modern networks, these are most commonly Ethernet, but other types are supported as well. IP addresses and VLANs can be assigned to interfaces.\n---\n\n# netbox_device_interface (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/device/#interface):\n\n> Interfaces in NetBox represent network interfaces used to exchange data with connected devices. On modern networks, these are most commonly Ethernet, but other types are supported as well. IP addresses and VLANs can be assigned to interfaces.\n\n## Example Usage\n\n```terraform\n// Assumes a device with ID 123 exists\nresource \"netbox_device_interface\" \"test\" {\n  name      = \"testinterface\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n- `type` (String)\n\n### Optional\n\n- `description` (String)\n- `enabled` (Boolean) Defaults to `true`.\n- `label` (String)\n- `lag_device_interface_id` (Number) If this device is a member of a LAG group, you can reference the LAG interface here.\n- `mgmtonly` (Boolean)\n- `mode` (String) Valid values are `access`, `tagged`, `tagged-all` and `q-in-q`.\n- `mtu` (Number)\n- `parent_device_interface_id` (Number) The netbox_device_interface id of the parent interface. Useful if this interface is a logical interface.\n- `speed` (Number)\n- `tagged_vlans` (Set of Number)\n- `tags` (Set of String)\n- `untagged_vlan` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `mac_address` (String) The MAC address as string from the first MAC address assigned to this interface, if any.\n- `mac_addresses` (Set of Object) (see [below for nested schema](#nestedatt--mac_addresses))\n- `tags_all` (Set of String)\n\n<a id=\"nestedatt--mac_addresses\"></a>\n### Nested Schema for `mac_addresses`\n\nRead-Only:\n\n- `description` (String)\n- `id` (Number)\n- `mac_address` (String)\n\n\n"
  },
  {
    "path": "docs/resources/device_module_bay.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_module_bay Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/modulebay/:\n  Module bays represent a space or slot within a device in which a field-replaceable module may be installed. A common example is that of a chassis-based switch such as the Cisco Nexus 9000 or Juniper EX9200. Modules in turn hold additional components that become available to the parent device.\n---\n\n# netbox_device_module_bay (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/modulebay/):\n\n> Module bays represent a space or slot within a device in which a field-replaceable module may be installed. A common example is that of a chassis-based switch such as the Cisco Nexus 9000 or Juniper EX9200. Modules in turn hold additional components that become available to the parent device.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name      = \"module bay 1\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `label` (String)\n- `position` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_power_outlet.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_power_outlet Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/poweroutlet/:\n  Power outlets represent the outlets on a power distribution unit (PDU) or other device that supplies power to dependent devices. Each power port may be assigned a physical type, and may be associated with a specific feed leg (where three-phase power is used) and/or a specific upstream power port. This association can be used to model the distribution of power within a device.\n  For example, imagine a PDU with one power port which draws from a three-phase feed and 48 power outlets arranged into three banks of 16 outlets each. Outlets 1-16 would be associated with leg A on the port, and outlets 17-32 and 33-48 would be associated with legs B and C, respectively.\n---\n\n# netbox_device_power_outlet (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/poweroutlet/):\n\n> Power outlets represent the outlets on a power distribution unit (PDU) or other device that supplies power to dependent devices. Each power port may be assigned a physical type, and may be associated with a specific feed leg (where three-phase power is used) and/or a specific upstream power port. This association can be used to model the distribution of power within a device.\n\nFor example, imagine a PDU with one power port which draws from a three-phase feed and 48 power outlets arranged into three banks of 16 outlets each. Outlets 1-16 would be associated with leg A on the port, and outlets 17-32 and 33-48 would be associated with legs B and C, respectively.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_power_outlet\" \"test\" {\n  device_id = netbox_device.test.id\n  name      = \"power outlet\"\n  type      = \"iec-60320-c5\"\n  feed_leg  = \"A\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `feed_leg` (String) One of [A, B, C].\n- `label` (String)\n- `mark_connected` (Boolean) Defaults to `false`.\n- `module_id` (Number)\n- `power_port_id` (Number)\n- `tags` (Set of String)\n- `type` (String) One of [iec-60320-c5, iec-60320-c7, iec-60320-c13, iec-60320-c15, iec-60320-c19, iec-60320-c21, iec-60309-p-n-e-4h, iec-60309-p-n-e-6h, iec-60309-p-n-e-9h, iec-60309-2p-e-4h, iec-60309-2p-e-6h, iec-60309-2p-e-9h, iec-60309-3p-e-4h, iec-60309-3p-e-6h, iec-60309-3p-e-9h, iec-60309-3p-n-e-4h, iec-60309-3p-n-e-6h, iec-60309-3p-n-e-9h, nema-1-15r, nema-5-15r, nema-5-20r, nema-5-30r, nema-5-50r, nema-6-15r, nema-6-20r, nema-6-30r, nema-6-50r, nema-10-30r, nema-10-50r, nema-14-20r, nema-14-30r, nema-14-50r, nema-14-60r, nema-15-15r, nema-15-20r, nema-15-30r, nema-15-50r, nema-15-60r, nema-l1-15r, nema-l5-15r, nema-l5-20r, nema-l5-30r, nema-l5-50r, nema-l6-15r, nema-l6-20r, nema-l6-30r, nema-l6-50r, nema-l10-30r, nema-l14-20r, nema-l14-30r, nema-l14-50r, nema-l14-60r, nema-l15-20r, nema-l15-30r, nema-l15-50r, nema-l15-60r, nema-l21-20r, nema-l21-30r, nema-l22-30r, CS6360C, CS6364C, CS8164C, CS8264C, CS8364C, CS8464C, ita-e, ita-f, ita-g, ita-h, ita-i, ita-j, ita-k, ita-l, ita-m, ita-n, ita-o, ita-multistandard, usb-a, usb-micro-b, usb-c, dc-terminal, hdot-cx, saf-d-grid, neutrik-powercon-20a, neutrik-powercon-32a, neutrik-powercon-true1, neutrik-powercon-true1-top, ubiquiti-smartpower, hardwired, other].\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_power_port.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_power_port Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/powerport/:\n  A power port is a device component which draws power from some external source (e.g. an upstream power outlet), and generally represents a power supply internal to a device.\n---\n\n# netbox_device_power_port (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/powerport/):\n\n> A power port is a device component which draws power from some external source (e.g. an upstream power outlet), and generally represents a power supply internal to a device.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_power_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"power port\"\n  maximum_draw   = 750\n  allocated_draw = 500\n  type           = \"iec-60320-c6\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `allocated_draw` (Number)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `label` (String)\n- `mark_connected` (Boolean) Defaults to `false`.\n- `maximum_draw` (Number)\n- `module_id` (Number)\n- `tags` (Set of String)\n- `type` (String) One of [iec-60320-c6, iec-60320-c8, iec-60320-c14, iec-60320-c16, iec-60320-c20, iec-60320-c22, iec-60309-p-n-e-4h, iec-60309-p-n-e-6h, iec-60309-p-n-e-9h, iec-60309-2p-e-4h, iec-60309-2p-e-6h, iec-60309-2p-e-9h, iec-60309-3p-e-4h, iec-60309-3p-e-6h, iec-60309-3p-e-9h, iec-60309-3p-n-e-4h, iec-60309-3p-n-e-6h, iec-60309-3p-n-e-9h, nema-1-15p, nema-5-15p, nema-5-20p, nema-5-30p, nema-5-50p, nema-6-15p, nema-6-20p, nema-6-30p, nema-6-50p, nema-10-30p, nema-10-50p, nema-14-20p, nema-14-30p, nema-14-50p, nema-14-60p, nema-15-15p, nema-15-20p, nema-15-30p, nema-15-50p, nema-15-60p, nema-l1-15p, nema-l5-15p, nema-l5-20p, nema-l5-30p, nema-l5-50p, nema-l6-15p, nema-l6-20p, nema-l6-30p, nema-l6-50p, nema-l10-30p, nema-l14-20p, nema-l14-30p, nema-l14-50p, nema-l14-60p, nema-l15-20p, nema-l15-30p, nema-l15-50p, nema-l15-60p, nema-l21-20p, nema-l21-30p, nema-l22-30p, cs6361c, cs6365c, cs8165c, cs8265c, cs8365c, cs8465c, ita-c, ita-e, ita-f, ita-ef, ita-g, ita-h, ita-i, ita-j, ita-k, ita-l, ita-m, ita-n, ita-o, usb-a, usb-b, usb-c, usb-mini-a, usb-mini-b, usb-micro-a, usb-micro-b, usb-micro-ab, usb-3-b, usb-3-micro-b, dc-terminal, saf-d-grid, neutrik-powercon-20, neutrik-powercon-32, neutrik-powercon-true1, neutrik-powercon-true1-top, ubiquiti-smartpower, hardwired, other].\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_primary_ip.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_primary_ip Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  This resource is used to define the primary IP for a given device. The primary IP is reflected in the device Netbox UI, which identifies the Primary IPv4 and IPv6 addresses.\n---\n\n# netbox_device_primary_ip (Resource)\n\nThis resource is used to define the primary IP for a given device. The primary IP is reflected in the device Netbox UI, which identifies the Primary IPv4 and IPv6 addresses.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_ip_address\" \"test_v4\" {\n  ip_address          = \"1.1.1.1/32\"\n  status              = \"active\"\n  device_interface_id = netbox_device_interface.test.id\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4\" {\n  device_id     = netbox_device.test.id\n  ip_address_id = netbox_ip_address.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `ip_address_id` (Number)\n\n### Optional\n\n- `ip_address_version` (Number) Defaults to `4`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/device_rear_port.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_rear_port Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/rearport/:\n  Like front ports, rear ports are pass-through ports which represent the continuation of a path from one cable to the next. Each rear port is defined with its physical type and a number of positions: Rear ports with more than one position can be mapped to multiple front ports. This can be useful for modeling instances where multiple paths share a common cable (for example, six discrete two-strand fiber connections sharing a 12-strand MPO cable).\n---\n\n# netbox_device_rear_port (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/rearport/):\n\n> Like front ports, rear ports are pass-through ports which represent the continuation of a path from one cable to the next. Each rear port is defined with its physical type and a number of positions: Rear ports with more than one position can be mapped to multiple front ports. This can be useful for modeling instances where multiple paths share a common cable (for example, six discrete two-strand fiber connections sharing a 12-strand MPO cable).\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"rear port 1\"\n  type           = \"8p8c\"\n  positions      = 2\n  mark_connected = true\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n- `positions` (Number)\n- `type` (String) One of [8p8c, 8p6c, 8p4c, 8p2c, 6p6c, 6p4c, 6p2c, 4p4c, 4p2c, gg45, tera-4p, tera-2p, tera-1p, 110-punch, bnc, f, n, mrj21, fc, lc, lc-pc, lc-upc, lc-apc, lsh, lsh-pc, lsh-upc, lsh-apc, mpo, mtrj, sc, sc-pc, sc-upc, sc-apc, st, cs, sn, sma-905, sma-906, urm-p2, urm-p4, urm-p8, splice, other].\n\n### Optional\n\n- `color_hex` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `label` (String)\n- `mark_connected` (Boolean) Defaults to `false`.\n- `module_id` (Number)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_role Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/devices/#device-roles:\n  Devices can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for core switches, distribution switches, and access switches within your network.\n---\n\n# netbox_device_role (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#device-roles):\n\n> Devices can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for core switches, distribution switches, and access switches within your network.\n\n## Example Usage\n\n```terraform\nresource \"netbox_device_role\" \"core_sw\" {\n  color_hex = \"ff00ff\"\n  name      = \"core-sw\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `color_hex` (String)\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `slug` (String)\n- `tags` (Set of String)\n- `vm_role` (Boolean) Defaults to `true`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/device_type.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_device_type Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/device-types/#device-types_1:\n  A device type represents a particular make and model of hardware that exists in the real world. Device types define the physical attributes of a device (rack height and depth) and its individual components (console, power, network interfaces, and so on).\n---\n\n# netbox_device_type (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/device-types/#device-types_1):\n\n> A device type represents a particular make and model of hardware that exists in the real world. Device types define the physical attributes of a device (rack height and depth) and its individual components (console, power, network interfaces, and so on).\n\n## Example Usage\n\n```terraform\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model           = \"test\"\n  part_number     = \"123\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `manufacturer_id` (Number)\n- `model` (String)\n\n### Optional\n\n- `is_full_depth` (Boolean)\n- `part_number` (String)\n- `slug` (String)\n- `subdevice_role` (String)\n- `tags` (Set of String)\n- `u_height` (Number) Defaults to `1.0`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/event_rule.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_event_rule Resource - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/event-rules/:\n  NetBox can be configured via Event Rules to transmit outgoing webhooks to remote systems in response to internal object changes. The receiver can act on the data in these webhook messages to perform related tasks.\n      Event rules can also execute custom scripts, enabling NetBox to run defined logic locally in response to object changes.\n---\n\n# netbox_event_rule (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/event-rules/):\n\n> NetBox can be configured via Event Rules to transmit outgoing webhooks to remote systems in response to internal object changes. The receiver can act on the data in these webhook messages to perform related tasks.\n\tEvent rules can also execute custom scripts, enabling NetBox to run defined logic locally in response to object changes.\n\n## Example Usage\n\n```terraform\nresource \"netbox_webhook\" \"test\" {\n  name        = \"my-webhook\"\n  payload_url = \"https://example.com/webhook\"\n}\n\nresource \"netbox_event_rule\" \"webhook\" {\n  name             = \"my-event-rule\"\n  content_types    = [\"dcim.site\", \"virtualization.cluster\"]\n  action_type      = \"webhook\"\n  action_object_id = netbox_webhook.test.id\n  event_types = [\n    \"object_created\",\n    \"object_updated\",\n    \"object_deleted\",\n    \"job_started\",\n    \"job_completed\",\n    \"job_failed\",\n    \"job_errored\"\n  ]\n}\n\nresource \"netbox_event_rule\" \"script\" {\n  name             = \"my-script-event-rule\"\n  content_types    = [\"dcim.site\"]\n  action_type      = \"script\"\n  action_object_id = 42 # existing NetBox Script ID\n  event_types      = [\"object_created\"]\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `action_object_id` (Number)\n- `action_type` (String) Valid values are `webhook` and `script`.\n- `content_types` (Set of String)\n- `event_types` (Set of String) The types of event which will trigger this rule. By default, valid values are `object_created`, `oject_updated`, `object_deleted`, `job_started`, `job_completed`, `job_failed` and `job_errored`.\n- `name` (String)\n\n### Optional\n\n- `conditions` (String)\n- `description` (String)\n- `enabled` (Boolean) Defaults to `true`.\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_group Resource - terraform-provider-netbox\"\nsubcategory: \"Authentication\"\ndescription: |-\n  This resource is used to manage groups.\n---\n\n# netbox_group (Resource)\n\nThis resource is used to manage groups.\n\n## Example Usage\n\n```terraform\nresource \"netbox_group\" \"test\" {\n  name = \"test-group\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String) Defaults to `\"\"`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/interface.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_interface Resource - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#interfaces:\n  Virtual machine interfaces behave similarly to device interfaces, and can be assigned to VRFs, and may have IP addresses, VLANs, and services attached to them. However, given their virtual nature, they lack properties pertaining to physical attributes. For example, VM interfaces do not have a physical type and cannot have cables attached to them.\n---\n\n# netbox_interface (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#interfaces):\n\n> Virtual machine interfaces behave similarly to device interfaces, and can be assigned to VRFs, and may have IP addresses, VLANs, and services attached to them. However, given their virtual nature, they lack properties pertaining to physical attributes. For example, VM interfaces do not have a physical type and cannot have cables attached to them.\n\n## Example Usage\n\n```terraform\n// Assume Netbox already has a VM whos name matches 'dc-west-myvm-20'\ndata \"netbox_virtual_machine\" \"myvm\" {\n  name_regex = \"dc-west-myvm-20\"\n}\n\nresource \"netbox_interface\" \"myvm_eth0\" {\n  name               = \"eth0\"\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n\n// Assume existing VLAN resources 'test1' and 'test2'\nresource \"netbox_interface\" \"myvm_eth1\" {\n  name               = \"eth1\"\n  enabled            = true\n  mac_address        = \"00:16:3E:A8:B5:D7\"\n  mode               = \"tagged\"\n  mtu                = 1440\n  tagged_vlans       = [netbox_vlan.test1.id]\n  untagged_vlan      = netbox_vlan.test2.id\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `virtual_machine_id` (Number)\n\n### Optional\n\n- `bridge_interface_id` (Number) ID of the bridge interface this interface belongs to.\n- `description` (String)\n- `enabled` (Boolean) Defaults to `true`.\n- `mac_address` (String)\n- `mode` (String) Valid values are `access`, `tagged` and `tagged-all`.\n- `mtu` (Number)\n- `tagged_vlans` (Set of Number)\n- `tags` (Set of String)\n- `type` (String, Deprecated)\n- `untagged_vlan` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/interface_template.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_interface_template Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/interfacetemplate/:\n  A template for a network interface that will be created on all instantiations of the parent device type. See the interface documentation for more detail.\n---\n\n# netbox_interface_template (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/interfacetemplate/):\n\n> A template for a network interface that will be created on all instantiations of the parent device type. See the interface documentation for more detail.\n\n## Example Usage\n\n```terraform\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"my-manufacturer\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model           = \"test-model\"\n  slug            = \"test-model\"\n  part_number     = \"test-part-number\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_interface_template\" \"test\" {\n  name           = \"eth0\"\n  description    = \"eth0 description\"\n  label          = \"eth0 label\"\n  device_type_id = netbox_device_type.test.id\n  type           = \"100base-tx\"\n  mgmt_only      = true\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `type` (String)\n\n### Optional\n\n- `description` (String)\n- `device_type_id` (Number) Exactly one of `device_type_id` or `module_type_id` must be given.\n- `label` (String)\n- `mgmt_only` (Boolean)\n- `module_type_id` (Number) Exactly one of `device_type_id` or `module_type_id` must be given.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/inventory_item.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_inventory_item Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/inventoryitem/:\n  Inventory items represent hardware components installed within a device, such as a power supply or CPU or line card. They are intended to be used primarily for inventory purposes.\n---\n\n# netbox_inventory_item (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/inventoryitem/):\n\n> Inventory items represent hardware components installed within a device, such as a power supply or CPU or line card. They are intended to be used primarily for inventory purposes.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id      = netbox_tenant.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"rear port\"\n  type           = \"8p8c\"\n  positions      = 1\n  mark_connected = true\n}\n\nresource \"netbox_inventory_item\" \"parent\" {\n  device_id = netbox_device.test.id\n  name      = \"Parent Item\"\n}\n\nresource \"netbox_inventory_item\" \"test\" {\n  device_id = netbox_device.test.id\n  name      = \"Child Item\"\n  parent_id = netbox_inventory_item.parent.id\n\n  component_type = \"dcim.rearport\"\n  component_id   = netbox_device_rear_port.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `name` (String)\n\n### Optional\n\n- `asset_tag` (String)\n- `component_id` (Number) Required when `component_type` is set.\n- `component_type` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `discovered` (Boolean) Defaults to `false`.\n- `label` (String)\n- `manufacturer_id` (Number)\n- `parent_id` (Number)\n- `part_id` (String)\n- `role_id` (Number)\n- `serial` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/inventory_item_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_inventory_item_role Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/inventoryitemrole/:\n  Inventory items can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for power supplies, fans, interface optics, etc.\n---\n\n# netbox_inventory_item_role (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/inventoryitemrole/):\n\n> Inventory items can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for power supplies, fans, interface optics, etc.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id      = netbox_tenant.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_inventory_item_role\" \"test\" {\n  name      = \"Role 1\"\n  slug      = \"role-1-slug\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_inventory_item\" \"parent\" {\n  device_id = netbox_device.test.id\n  name      = \"Inventory Item 1\"\n  role_id   = netbox_inventory_item_role.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `color_hex` (String)\n- `name` (String)\n- `slug` (String)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/ip_address.md",
    "content": "---\npage_title: \"netbox_ip_address Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#ip-addresses:\n  An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.\n  Like a prefix, an IP address can optionally be assigned to a VRF (otherwise, it will appear in the \"global\" table). IP addresses are automatically arranged under parent prefixes within their respective VRFs according to the IP hierarchy.\n---\n\n# netbox_ip_address (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#ip-addresses):\n\n> An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.\n>\n> Like a prefix, an IP address can optionally be assigned to a VRF (otherwise, it will appear in the \"global\" table). IP addresses are automatically arranged under parent prefixes within their respective VRFs according to the IP hierarchy.\n\n## Example Usage\n\n### Creating an IP address that is assigned to a virtual machine interface\n\nStarting with provider version 3.5.0, you can use the `virtual_machine_interface_id` attribute to assign an IP address to a virtual machine interface.\nYou can also use the `interface_id` and `object_type` attributes instead.\n\nWith `virtual_machine_interface_id`:\n```terraform\n// Assuming a virtual machine with the id `123` exists\nresource \"netbox_interface\" \"this\" {\n  name               = \"eth0\"\n  virtual_machine_id = 123\n}\n\nresource \"netbox_ip_address\" \"this\" {\n  ip_address                   = \"10.0.0.60/24\"\n  status                       = \"active\"\n  virtual_machine_interface_id = netbox_interface.this.id\n}\n```\n\nWith `object_type` and `interface_id`:\n```terraform\n// Assuming a virtual machine with the id `123` exists\nresource \"netbox_interface\" \"this\" {\n  name               = \"eth0\"\n  virtual_machine_id = 123\n}\n\nresource \"netbox_ip_address\" \"this\" {\n  ip_address   = \"10.0.0.60/24\"\n  status       = \"active\"\n  interface_id = netbox_interface.this.id\n  object_type  = \"virtualization.vminterface\"\n}\n```\n\n### Creating an IP address that is assigned to a device interface\n\nStarting with provider version 3.5.0, you can use the `device_interface_id` attribute to assign an IP address to a device interface.\nYou can also use the `interface_id` and `object_type` attributes instead.\n\nWith `device_interface_id`:\n```terraform\n// Assuming a device with the id `123` exists\nresource \"netbox_device_interface\" \"this\" {\n  name      = \"eth0\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"this\" {\n  ip_address          = \"10.0.0.60/24\"\n  status              = \"active\"\n  device_interface_id = netbox_device_interface.this.id\n}\n```\n\nWith `object_type` and `interface_id`:\n```terraform\n// Assuming a device with the id `123` exists\nresource \"netbox_device_interface\" \"this\" {\n  name      = \"eth0\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"this\" {\n  ip_address   = \"10.0.0.60/24\"\n  status       = \"active\"\n  interface_id = netbox_device_interface.this.id\n  object_type  = \"dcim.interface\"\n}\n```\n\n### Creating an IP address that is not assigned to anything\n\nYou can create an IP address that is not assigned to anything by omitting the attributes mentioned above.\n\n```terraform\nresource \"netbox_ip_address\" \"this\" {\n  ip_address = \"10.0.0.50/24\"\n  status     = \"reserved\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `ip_address` (String)\n- `status` (String) Valid values are `active`, `reserved`, `deprecated`, `dhcp` and `slaac`.\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `device_interface_id` (Number) Conflicts with `interface_id` and `virtual_machine_interface_id`.\n- `dns_name` (String)\n- `interface_id` (Number) Required when `object_type` is set.\n- `nat_inside_address_id` (Number)\n- `object_type` (String) Valid values are `virtualization.vminterface` and `dcim.interface`. Required when `interface_id` is set.\n- `role` (String) Valid values are `loopback`, `secondary`, `anycast`, `vip`, `vrrp`, `hsrp`, `glbp` and `carp`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `virtual_machine_interface_id` (Number) Conflicts with `interface_id` and `device_interface_id`.\n- `vrf_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `nat_outside_addresses` (List of Object) (see [below for nested schema](#nestedatt--nat_outside_addresses))\n- `tags_all` (Set of String)\n\n<a id=\"nestedatt--nat_outside_addresses\"></a>\n### Nested Schema for `nat_outside_addresses`\n\nRead-Only:\n\n- `address_family` (Number)\n- `id` (Number)\n- `ip_address` (String)\n\n\n"
  },
  {
    "path": "docs/resources/ip_range.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_ip_range Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#ip-ranges:\n  This model represents an arbitrary range of individual IPv4 or IPv6 addresses, inclusive of its starting and ending addresses. For instance, the range 192.0.2.10 to 192.0.2.20 has eleven members. (The total member count is available as the size property on an IPRange instance.) Like prefixes and IP addresses, each IP range may optionally be assigned to a VRF and/or tenant.\n---\n\n# netbox_ip_range (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#ip-ranges):\n\n> This model represents an arbitrary range of individual IPv4 or IPv6 addresses, inclusive of its starting and ending addresses. For instance, the range 192.0.2.10 to 192.0.2.20 has eleven members. (The total member count is available as the size property on an IPRange instance.) Like prefixes and IP addresses, each IP range may optionally be assigned to a VRF and/or tenant.\n\n## Example Usage\n\n```terraform\nresource \"netbox_ip_range\" \"cust_a_prod\" {\n  start_address = \"10.0.0.1/24\"\n  end_address   = \"10.0.0.50/24\"\n  tags          = [\"customer-a\", \"prod\"]\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `end_address` (String)\n- `start_address` (String)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `role_id` (Number)\n- `status` (String) Valid values are `active`, `reserved` and `deprecated`. Defaults to `active`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `vrf_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `size` (Number) The total member count of the IP range.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/ipam_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_ipam_role Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#prefixvlan-roles:\n  A role indicates the function of a prefix or VLAN. For example, you might define Data, Voice, and Security roles. Generally, a prefix will be assigned the same functional role as the VLAN to which it is assigned (if any).\n---\n\n# netbox_ipam_role (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#prefixvlan-roles):\n\n> A role indicates the function of a prefix or VLAN. For example, you might define Data, Voice, and Security roles. Generally, a prefix will be assigned the same functional role as the VLAN to which it is assigned (if any).\n\n## Example Usage\n\n```terraform\nresource \"netbox_ipam_role\" \"test_basic\" {\n  name = \"test\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `slug` (String)\n- `weight` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/location.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_location Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/sites-and-racks/#locations:\n  Racks and devices can be grouped by location within a site. A location may represent a floor, room, cage, or similar organizational unit. Locations can be nested to form a hierarchy. For example, you may have floors within a site, and rooms within a floor.\n  Each location must have a name that is unique within its parent site and location, if any.\n---\n\n# netbox_location (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#locations):\n\n> Racks and devices can be grouped by location within a site. A location may represent a floor, room, cage, or similar organizational unit. Locations can be nested to form a hierarchy. For example, you may have floors within a site, and rooms within a floor.\n\nEach location must have a name that is unique within its parent site and location, if any.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name        = \"test\"\n  description = \"my description\"\n  site_id     = netbox_site.test.id\n  tenant_id   = netbox_tenant.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `site_id` (Number)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `facility` (String)\n- `parent_id` (Number)\n- `slug` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/mac_address.md",
    "content": "---\npage_title: \"netbox_mac_address Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://netboxlabs.com/docs/netbox/models/dcim/macaddress/:\n  A MAC address object in NetBox comprises a single Ethernet link layer address, and represents a MAC address as reported by or assigned to a network interface. MAC addresses can be assigned to device and virtual machine interfaces. A MAC address can be specified as the primary MAC address for a given device or VM interface.\n---\n\n# netbox_mac_address (Resource)\n\nFrom the [official documentation](https://netboxlabs.com/docs/netbox/models/dcim/macaddress/):\n\n> A MAC address object in NetBox comprises a single Ethernet link layer address, and represents a MAC address as reported by or assigned to a network interface. MAC addresses can be assigned to device and virtual machine interfaces. A MAC address can be specified as the primary MAC address for a given device or VM interface.\n\n## Example Usage\n\n### Creating a MAC address that is assigned to a virtual machine interface\n\nWith `virtual_machine_interface_id`:\n```terraform\n// Assuming a virtual machine with the id `123` exists\nresource \"netbox_interface\" \"this\" {\n  name               = \"eth0\"\n  virtual_machine_id = 123\n}\n\nresource \"netbox_mac_address\" \"this\" {\n  mac_address                  = \"00:1A:2B:3C:4D:5E\"\n  virtual_machine_interface_id = netbox_interface.this.id\n}\n```\n\nWith `object_type` and `interface_id`:\n```terraform\n// Assuming a virtual machine with the id `123` exists\nresource \"netbox_interface\" \"this\" {\n  name               = \"eth0\"\n  virtual_machine_id = 123\n}\n\nresource \"netbox_mac_address\" \"this\" {\n  mac_address  = \"00:1A:2B:3C:4D:5E\"\n  interface_id = netbox_interface.this.id\n  object_type  = \"virtualization.vminterface\"\n}\n```\n\n### Creating a MAC address that is assigned to a device interface\n\nWith `device_interface_id`:\n```terraform\n// Assuming a device with the id `123` exists\nresource \"netbox_device_interface\" \"this\" {\n  name      = \"eth0\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_mac_address\" \"this\" {\n  mac_address         = \"00:1A:2B:3C:4D:5E\"\n  device_interface_id = netbox_device_interface.this.id\n}\n```\n\nWith `object_type` and `interface_id`:\n```terraform\n// Assuming a device with the id `123` exists\nresource \"netbox_device_interface\" \"this\" {\n  name      = \"eth0\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_mac_address\" \"this\" {\n  mac_address  = \"00:1A:2B:3C:4D:5E\"\n  interface_id = netbox_device_interface.this.id\n  object_type  = \"dcim.interface\"\n}\n```\n\n### Creating a MAC address that is not assigned to anything\n\nYou can create a MAC address that is not assigned to anything by omitting the attributes mentioned above.\n\n```terraform\nresource \"netbox_mac_address\" \"this\" {\n  mac_address = \"00:1A:2B:3C:4D:5E\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `mac_address` (String)\n\n### Optional\n\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `device_interface_id` (Number) Conflicts with `interface_id` and `virtual_machine_interface_id`.\n- `interface_id` (Number) Required when `object_type` is set.\n- `object_type` (String) Valid values are `virtualization.vminterface` and `dcim.interface`. Required when `interface_id` is set.\n- `tags` (Set of String)\n- `virtual_machine_interface_id` (Number) Conflicts with `interface_id` and `device_interface_id`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/manufacturer.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_manufacturer Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/device-types/#manufacturers:\n  A manufacturer represents the \"make\" of a device; e.g. Cisco or Dell. Each device type must be assigned to a manufacturer. (Inventory items and platforms may also be associated with manufacturers.) Each manufacturer must have a unique name and may have a description assigned to it.\n---\n\n# netbox_manufacturer (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/device-types/#manufacturers):\n\n> A manufacturer represents the \"make\" of a device; e.g. Cisco or Dell. Each device type must be assigned to a manufacturer. (Inventory items and platforms may also be associated with manufacturers.) Each manufacturer must have a unique name and may have a description assigned to it.\n\n## Example Usage\n\n```terraform\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"testmanufacturer\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/module.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_module Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/module/:\n  A module is a field-replaceable hardware component installed within a device which houses its own child components. The most common example is a chassis-based router or switch.\n  Similar to devices, modules are instantiated from module types, and any components associated with the module type are automatically instantiated on the new model. Each module must be installed within a module bay on a device, and each module bay may have only one module installed in it.\n---\n\n# netbox_module (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/module/):\n\n> A module is a field-replaceable hardware component installed within a device which houses its own child components. The most common example is a chassis-based router or switch.\n\nSimilar to devices, modules are instantiated from module types, and any components associated with the module type are automatically instantiated on the new model. Each module must be installed within a module bay on a device, and each module bay may have only one module installed in it.\n\n## Example Usage\n\n```terraform\n# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name      = \"SFP\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"Dell\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model           = \"Networking\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id      = netbox_device.test.id\n  module_bay_id  = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status         = \"active\"\n\n  description = \"SFP card\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `device_id` (Number)\n- `module_bay_id` (Number)\n- `module_type_id` (Number)\n- `status` (String) One of [offline, active, planned, staged, failed, decommissioning].\n\n### Optional\n\n- `asset_tag` (String)\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `serial` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/module_type.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_module_type Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/moduletype/:\n  A module type represents a specific make and model of hardware component which is installable within a device's module bay and has its own child components. For example, consider a chassis-based switch or router with a number of field-replaceable line cards. Each line card has its own model number and includes a certain set of components such as interfaces. Each module type may have a manufacturer, model number, and part number assigned to it.\n---\n\n# netbox_module_type (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/moduletype/):\n\n> A module type represents a specific make and model of hardware component which is installable within a device's module bay and has its own child components. For example, consider a chassis-based switch or router with a number of field-replaceable line cards. Each line card has its own model number and includes a certain set of components such as interfaces. Each module type may have a manufacturer, model number, and part number assigned to it.\n\n## Example Usage\n\n```terraform\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"Dell\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model           = \"Networking\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `manufacturer_id` (Number)\n- `model` (String)\n\n### Optional\n\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `part_number` (String)\n- `tags` (Set of String)\n- `weight` (Number)\n- `weight_unit` (String) One of [kg, g, lb, oz]. Required when `weight` is set.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/permission.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_permission Resource - terraform-provider-netbox\"\nsubcategory: \"Authentication\"\ndescription: |-\n  This resource manages the object-based permissions for Netbox users, built into the application.\n  Object-based permissions enable an administrator to grant users or groups the ability to perform an action on arbitrary subsets of objects in NetBox, rather than all objects of a certain type.\n  For more information, see the Netbox Object-Based Permissions Docs. https://docs.netbox.dev/en/stable/administration/permissions/\n---\n\n# netbox_permission (Resource)\n\nThis resource manages the object-based permissions for Netbox users, built into the application.\n\n> Object-based permissions enable an administrator to grant users or groups the ability to perform an action on arbitrary subsets of objects in NetBox, rather than all objects of a certain type.\n> For more information, see the [Netbox Object-Based Permissions Docs.](https://docs.netbox.dev/en/stable/administration/permissions/)\n\n## Example Usage\n\n```terraform\nresource \"netbox_user\" \"test\" {\n  username = \"johndoe\"\n  password = \"Abcdefghijkl1\"\n  active   = true\n  staff    = true\n}\n\nresource \"netbox_permission\" \"test\" {\n  name         = \"test\"\n  description  = \"my description\"\n  enabled      = true\n  object_types = [\"ipam.prefix\"]\n  actions      = [\"add\", \"change\"]\n  users        = [netbox_user.test.id]\n  constraints = jsonencode([{\n    \"status\" = \"active\"\n  }])\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `actions` (Set of String) A list actions that are allowed on the object types. Acceptable values are `view`, `add`, `change`, or `delete`.\n- `name` (String) The name of the permission object.\n- `object_types` (Set of String) A list of object types that the permission object allows access to. Should be in a form the API can accept. For example: `circuits.provider`, `dcim.inventoryitem`, etc.\n\n### Optional\n\n- `constraints` (String) A JSON string of an arbitrary filter used to limit the granted action(s) to a specific subset of objects. For more information on correct syntax, see https://docs.netbox.dev/en/stable/administration/permissions/#constraints.\n- `description` (String) The description of the permission object.\n- `enabled` (Boolean) Whether the permission object is enabled or not. Defaults to `true`.\n- `groups` (Set of Number) A list of group IDs that have been assigned to this permission object.\n- `users` (Set of Number) A list of user IDs that have been assigned to this permission object.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/platform.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_platform Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/devices/#platforms:\n  A platform defines the type of software running on a device or virtual machine. This can be helpful to model when it is necessary to distinguish between different versions or feature sets. Note that two devices of the same type may be assigned different platforms: For example, one Juniper MX240 might run Junos 14 while another runs Junos 15.\n---\n\n# netbox_platform (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#platforms):\n\n> A platform defines the type of software running on a device or virtual machine. This can be helpful to model when it is necessary to distinguish between different versions or feature sets. Note that two devices of the same type may be assigned different platforms: For example, one Juniper MX240 might run Junos 14 while another runs Junos 15.\n\n## Example Usage\n\n```terraform\n// Resource for PanOS (e.g. Panorama from Palo Alto)\nresource \"netbox_platform\" \"PANOS\" {\n  name = \"PANOS\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `manufacturer_id` (Number)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/power_feed.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_power_feed Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/powerfeed/:\n  A power feed represents the distribution of power from a power panel to a particular device, typically a power distribution unit (PDU). The power port (inlet) on a device can be connected via a cable to a power feed. A power feed may optionally be assigned to a rack to allow more easily tracking the distribution of power among racks.\n---\n\n# netbox_power_feed (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/powerfeed/):\n\n> A power feed represents the distribution of power from a power panel to a particular device, typically a power distribution unit (PDU). The power port (inlet) on a device can be connected via a cable to a power feed. A power feed may optionally be assigned to a rack to allow more easily tracking the distribution of power among racks.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site\" \"test\" {\n  name   = \"Site 1\"\n  status = \"active\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name    = \"Location 1\"\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_power_panel\" \"test\" {\n  name        = \"Power Panel 1\"\n  site_id     = netbox_site.test.id\n  location_id = netbox_location.test.id\n}\n\nresource \"netbox_power_feed\" \"test\" {\n  power_panel_id          = netbox_power_panel.test.id\n  name                    = \"Power Feed 1\"\n  status                  = \"active\"\n  type                    = \"primary\"\n  supply                  = \"ac\"\n  phase                   = \"single-phase\"\n  voltage                 = 250\n  amperage                = 100\n  max_percent_utilization = 80\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `amperage` (Number)\n- `max_percent_utilization` (Number)\n- `name` (String)\n- `phase` (String) One of [single-phase, three-phase].\n- `power_panel_id` (Number)\n- `status` (String) One of [offline, active, planned, failed].\n- `supply` (String) One of [ac, dc].\n- `type` (String) One of [primary, redundant].\n- `voltage` (Number)\n\n### Optional\n\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `mark_connected` (Boolean) Defaults to `false`.\n- `rack_id` (Number)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/power_panel.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_power_panel Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/powerpanel/:\n  A power panel represents the origin point in NetBox for electrical power being disseminated by one or more power feeds. In a data center environment, one power panel often serves a group of racks, with an individual power feed extending to each rack, though this is not always the case. It is common to have two sets of panels and feeds arranged in parallel to provide redundant power to each rack.\n---\n\n# netbox_power_panel (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/powerpanel/):\n\n> A power panel represents the origin point in NetBox for electrical power being disseminated by one or more power feeds. In a data center environment, one power panel often serves a group of racks, with an individual power feed extending to each rack, though this is not always the case. It is common to have two sets of panels and feeds arranged in parallel to provide redundant power to each rack.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site\" \"test\" {\n  name   = \"Site 1\"\n  status = \"active\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name    = \"Location 1\"\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_power_panel\" \"test\" {\n  name        = \"Power Panel 1\"\n  site_id     = netbox_site.test.id\n  location_id = netbox_location.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `site_id` (Number)\n\n### Optional\n\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `location_id` (Number)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/prefix.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_prefix Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#prefixes:\n  A prefix is an IPv4 or IPv6 network and mask expressed in CIDR notation (e.g. 192.0.2.0/24). A prefix entails only the \"network portion\" of an IP address: All bits in the address not covered by the mask must be zero. (In other words, a prefix cannot be a specific IP address.)\n  Prefixes are automatically organized by their parent aggregates. Additionally, each prefix can be assigned to a particular site and virtual routing and forwarding instance (VRF). Each VRF represents a separate IP space or routing table. All prefixes not assigned to a VRF are considered to be in the \"global\" table.\n---\n\n# netbox_prefix (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#prefixes):\n\n> A prefix is an IPv4 or IPv6 network and mask expressed in CIDR notation (e.g. 192.0.2.0/24). A prefix entails only the \"network portion\" of an IP address: All bits in the address not covered by the mask must be zero. (In other words, a prefix cannot be a specific IP address.)\n>\n> Prefixes are automatically organized by their parent aggregates. Additionally, each prefix can be assigned to a particular site and virtual routing and forwarding instance (VRF). Each VRF represents a separate IP space or routing table. All prefixes not assigned to a VRF are considered to be in the \"global\" table.\n\n## Example Usage\n\n```terraform\nresource \"netbox_prefix\" \"my_prefix\" {\n  prefix      = \"10.0.0.0/24\"\n  status      = \"active\"\n  description = \"test prefix\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `prefix` (String)\n- `status` (String) Valid values are `active`, `container`, `reserved` and `deprecated`.\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `is_pool` (Boolean)\n- `location_id` (Number) Conflicts with `site_id`, `site_group_id` and `region_id`.\n- `mark_utilized` (Boolean)\n- `region_id` (Number) Conflicts with `location_id`, `site_id` and `site_group_id`.\n- `role_id` (Number)\n- `site_group_id` (Number) Conflicts with `location_id`, `site_id` and `region_id`.\n- `site_id` (Number) Conflicts with `location_id`, `site_group_id` and `region_id`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `vlan_id` (Number)\n- `vrf_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/primary_ip.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_primary_ip Resource - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  This resource is used to define the primary IP for a given virtual machine. The primary IP is reflected in the Virtual machine Netbox UI, which identifies the Primary IPv4 and IPv6 addresses.\n---\n\n# netbox_primary_ip (Resource)\n\nThis resource is used to define the primary IP for a given virtual machine. The primary IP is reflected in the Virtual machine Netbox UI, which identifies the Primary IPv4 and IPv6 addresses.\n\n## Example Usage\n\n```terraform\n// Assumes Netbox already has a VM whos name matches 'dc-west-myvm-20'\ndata \"netbox_virtual_machine\" \"myvm\" {\n  name_regex = \"dc-west-myvm-20\"\n}\n\nresource \"netbox_interface\" \"myvm_eth0\" {\n  name               = \"eth0\"\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n\nresource \"netbox_ip_address\" \"myvm_ip\" {\n  ip_address   = \"10.0.0.60/24\"\n  status       = \"active\"\n  interface_id = netbox_interface.myvm_eth0.id\n}\n\nresource \"netbox_primary_ip\" \"myvm_primary_ip\" {\n  ip_address_id      = netbox_ip_address.myvm_ip.id\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `ip_address_id` (Number)\n- `virtual_machine_id` (Number)\n\n### Optional\n\n- `ip_address_version` (Number) Defaults to `4`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/rack.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_rack Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/rack/:\n  The rack model represents a physical two- or four-post equipment rack in which devices can be installed. Each rack must be assigned to a site, and may optionally be assigned to a location within that site. Racks can also be organized by user-defined functional roles. The name and facility ID of each rack within a location must be unique.\n  Rack height is measured in rack units (U); racks are commonly between 42U and 48U tall, but NetBox allows you to define racks of arbitrary height. A toggle is provided to indicate whether rack units are in ascending (from the ground up) or descending order.\n  Each rack is assigned a name and (optionally) a separate facility ID. This is helpful when leasing space in a data center your organization does not own: The facility will often assign a seemingly arbitrary ID to a rack (for example, \"M204.313\") whereas internally you refer to is simply as \"R113.\" A unique serial number and asset tag may also be associated with each rack.\n---\n\n# netbox_rack (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/rack/):\n\n> The rack model represents a physical two- or four-post equipment rack in which devices can be installed. Each rack must be assigned to a site, and may optionally be assigned to a location within that site. Racks can also be organized by user-defined functional roles. The name and facility ID of each rack within a location must be unique.\n\nRack height is measured in rack units (U); racks are commonly between 42U and 48U tall, but NetBox allows you to define racks of arbitrary height. A toggle is provided to indicate whether rack units are in ascending (from the ground up) or descending order.\n\nEach rack is assigned a name and (optionally) a separate facility ID. This is helpful when leasing space in a data center your organization does not own: The facility will often assign a seemingly arbitrary ID to a rack (for example, \"M204.313\") whereas internally you refer to is simply as \"R113.\" A unique serial number and asset tag may also be associated with each rack.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site\" \"test\" {\n  name   = \"test\"\n  status = \"active\"\n}\n\nresource \"netbox_rack\" \"test\" {\n  name     = \"test\"\n  site_id  = netbox_site.test.id\n  status   = \"reserved\"\n  width    = 19\n  u_height = 48\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `site_id` (Number)\n- `status` (String) Valid values are `reserved`, `available`, `planned`, `active` and `deprecated`.\n\n### Optional\n\n- `asset_tag` (String)\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `desc_units` (Boolean) If rack units are descending. Defaults to `false`.\n- `description` (String)\n- `facility_id` (String)\n- `form_factor` (String) Valid values are `2-post-frame`, `4-post-frame`, `4-post-cabinet`, `wall-frame`, `wall-frame-vertical`, `wall-cabinet` and `wall-cabinet-vertical`.\n- `location_id` (Number)\n- `max_weight` (Number)\n- `mounting_depth` (Number)\n- `outer_depth` (Number)\n- `outer_unit` (String) Valid values are `mm` and `in`. Required when `outer_width` and `outer_depth` is set.\n- `outer_width` (Number)\n- `role_id` (Number)\n- `serial` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `u_height` (Number)\n- `weight` (Number)\n- `weight_unit` (String) Valid values are `kg`, `g`, `lb` and `oz`. Required when `weight` and `max_weight` is set.\n- `width` (Number) Valid values are `10`, `19`, `21` and `23`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/rack_reservation.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_rack_reservation Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/rackreservation/:\n  Users can reserve specific units within a rack for future use. An arbitrary set of units within a rack can be associated with a single reservation, but reservations cannot span multiple racks. A description is required for each reservation, reservations may optionally be associated with a specific tenant.\n---\n\n# netbox_rack_reservation (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/rackreservation/):\n\n> Users can reserve specific units within a rack for future use. An arbitrary set of units within a rack can be associated with a single reservation, but reservations cannot span multiple racks. A description is required for each reservation, reservations may optionally be associated with a specific tenant.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site\" \"test\" {\n  name   = \"test\"\n  status = \"active\"\n}\n\nresource \"netbox_rack\" \"test\" {\n  name     = \"test\"\n  site_id  = netbox_site.test.id\n  status   = \"active\"\n  width    = 10\n  u_height = 40\n}\nresource \"netbox_rack_reservation\" \"test\" {\n  rack_id     = netbox_rack.test.id\n  units       = [1, 2, 3, 4, 5]\n  user_id     = 1\n  description = \"my description\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `description` (String)\n- `rack_id` (Number)\n- `units` (Set of Number)\n- `user_id` (Number)\n\n### Optional\n\n- `comments` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/rack_role.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_rack_role Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/dcim/rackrole/:\n  Each rack can optionally be assigned a user-defined functional role. For example, you might designate a rack for compute or storage resources, or to house colocated customer devices.\n---\n\n# netbox_rack_role (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/rackrole/):\n\n> Each rack can optionally be assigned a user-defined functional role. For example, you might designate a rack for compute or storage resources, or to house colocated customer devices.\n\n## Example Usage\n\n```terraform\nresource \"netbox_rack_role\" \"test\" {\n  name      = \"test\"\n  color_hex = \"111111\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `color_hex` (String)\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `slug` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/rack_type.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_rack_type Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://netboxlabs.com/docs/netbox/en/stable/models/dcim/racktype/:\n  A rack type defines the physical characteristics of a particular model of rack.\n---\n\n# netbox_rack_type (Resource)\n\nFrom the [official documentation](https://netboxlabs.com/docs/netbox/en/stable/models/dcim/racktype/):\n\n> A rack type defines the physical characteristics of a particular model of rack.\n\n## Example Usage\n\n```terraform\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"my-manufacturer\"\n}\n\nresource \"netbox_rack_type\" \"test\" {\n  model             = \"mymodel\"\n  manufacturer_id   = netbox_manufacturer.test.id\n  width             = 19\n  u_height          = 48\n  starting_unit     = 1\n  form_factor       = \"2-post-frame\"\n  description       = \"My description\"\n  outer_width       = 10\n  outer_depth       = 15\n  outer_unit        = \"mm\"\n  weight            = 15\n  max_weight        = 20\n  weight_unit       = \"kg\"\n  mounting_depth_mm = 21\n  comments          = \"My comments\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `form_factor` (String) Valid values are `2-post-frame`, `4-post-frame`, `4-post-cabinet`, `wall-frame`, `wall-frame-vertical`, `wall-cabinet` and `wall-cabinet-vertical`.\n- `model` (String)\n- `starting_unit` (Number)\n- `u_height` (Number)\n- `width` (Number) Valid values are `10`, `19`, `21` and `23`.\n\n### Optional\n\n- `comments` (String)\n- `description` (String)\n- `manufacturer_id` (Number)\n- `max_weight` (Number)\n- `mounting_depth_mm` (Number)\n- `outer_depth` (Number)\n- `outer_unit` (String) Valid values are `mm` and `in`. Required when `outer_width` and `outer_depth` is set.\n- `outer_width` (Number)\n- `slug` (String)\n- `tags` (Set of String)\n- `weight` (Number)\n- `weight_unit` (String) Valid values are `kg`, `g`, `lb` and `oz`. Required when `weight` and `max_weight` is set.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/region.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_region Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/sites-and-racks/#regions:\n  Sites can be arranged geographically using regions. A region might represent a continent, country, city, campus, or other area depending on your use case. Regions can be nested recursively to construct a hierarchy. For example, you might define several country regions, and within each of those several state or city regions to which sites are assigned.\n  Each region must have a name that is unique within its parent region, if any.\n---\n\n# netbox_region (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#regions):\n\n> Sites can be arranged geographically using regions. A region might represent a continent, country, city, campus, or other area depending on your use case. Regions can be nested recursively to construct a hierarchy. For example, you might define several country regions, and within each of those several state or city regions to which sites are assigned.\n>\n> Each region must have a name that is unique within its parent region, if any.\n\n## Example Usage\n\n```terraform\nresource \"netbox_region\" \"test\" {\n  name        = \"test\"\n  description = \"test description\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `parent_region_id` (Number)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/rir.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_rir Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs:\n  Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which \"owns\" certain address space. There also exist lower-tier registries which serve particular geographic areas.\n---\n\n# netbox_rir (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs):\n\n> Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which \"owns\" certain address space. There also exist lower-tier registries which serve particular geographic areas.\n\n## Example Usage\n\n```terraform\nresource \"netbox_rir\" \"test\" {\n  name        = \"test\"\n  description = \"my description\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `is_private` (Boolean) Defaults to `false`.\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/route_target.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_route_target Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/ipam/routetarget/:\n  A route target is a particular type of extended BGP community used to control the redistribution of routes among VRF tables in a network. Route targets can be assigned to individual VRFs in NetBox as import or export targets (or both) to model this exchange in an L3VPN. Each route target must be given a unique name, which should be in a format prescribed by RFC 4364, similar to a VR route distinguisher.\n---\n\n# netbox_route_target (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/ipam/routetarget/):\n\n> A route target is a particular type of extended BGP community used to control the redistribution of routes among VRF tables in a network. Route targets can be assigned to individual VRFs in NetBox as import or export targets (or both) to model this exchange in an L3VPN. Each route target must be given a unique name, which should be in a format prescribed by RFC 4364, similar to a VR route distinguisher.\n\n## Example Usage\n\n```terraform\nresource \"netbox_tenant\" \"test\" {\n  name = \"test\"\n}\nresource \"netbox_route_target\" \"test\" {\n  name        = \"test\"\n  description = \"my description\"\n  tenant_id   = netbox_tenant.test.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/service.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_service Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/services/#services:\n  A service represents a layer four TCP or UDP service available on a device or virtual machine. For example, you might want to document that an HTTP service is running on a device. Each service includes a name, protocol, and port number; for example, \"SSH (TCP/22)\" or \"DNS (UDP/53).\"\n  A service may optionally be bound to one or more specific IP addresses belonging to its parent device or VM. (If no IP addresses are bound, the service is assumed to be reachable via any assigned IP address.\n---\n\n# netbox_service (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/services/#services):\n\n> A service represents a layer four TCP or UDP service available on a device or virtual machine. For example, you might want to document that an HTTP service is running on a device. Each service includes a name, protocol, and port number; for example, \"SSH (TCP/22)\" or \"DNS (UDP/53).\"\n>\n> A service may optionally be bound to one or more specific IP addresses belonging to its parent device or VM. (If no IP addresses are bound, the service is assumed to be reachable via any assigned IP address.\n\n## Example Usage\n\n```terraform\n// Assumes Netbox already has a VM whos name matches 'dc-west-myvm-20'\ndata \"netbox_virtual_machine\" \"myvm\" {\n  name_regex = \"dc-west-myvm-20\"\n}\n\nresource \"netbox_service\" \"ssh\" {\n  name               = \"ssh\"\n  ports              = [22]\n  protocol           = \"tcp\"\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `protocol` (String) Valid values are `tcp`, `udp` and `sctp`.\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `device_id` (Number) Exactly one of `virtual_machine_id` or `device_id` must be given.\n- `port` (Number, Deprecated) Exactly one of `port` or `ports` must be given.\n- `ports` (Set of Number) Exactly one of `port` or `ports` must be given.\n- `tags` (Set of String)\n- `virtual_machine_id` (Number) Exactly one of `virtual_machine_id` or `device_id` must be given.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/site.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_site Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/sites-and-racks/#sites:\n  How you choose to employ sites when modeling your network may vary depending on the nature of your organization, but generally a site will equate to a building or campus. For example, a chain of banks might create a site to represent each of its branches, a site for its corporate headquarters, and two additional sites for its presence in two colocation facilities.\n  Each site must be assigned a unique name and may optionally be assigned to a region and/or tenant.\n---\n\n# netbox_site (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#sites):\n\n> How you choose to employ sites when modeling your network may vary depending on the nature of your organization, but generally a site will equate to a building or campus. For example, a chain of banks might create a site to represent each of its branches, a site for its corporate headquarters, and two additional sites for its presence in two colocation facilities.\n>\n> Each site must be assigned a unique name and may optionally be assigned to a region and/or tenant.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site\" \"example1\" {\n  name      = \"Example site 1\"\n  asn       = 1337\n  facility  = \"Data center\"\n  latitude  = \"-45.4085\"\n  longitude = \"30.1496\"\n  status    = \"staging\"\n  timezone  = \"Africa/Johannesburg\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `asn_ids` (Set of Number)\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `facility` (String)\n- `group_id` (Number)\n- `latitude` (Number)\n- `longitude` (Number)\n- `physical_address` (String)\n- `region_id` (Number)\n- `shipping_address` (String)\n- `slug` (String)\n- `status` (String) Valid values are `planned`, `staging`, `active`, `decommissioning` and `retired`. Defaults to `active`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `timezone` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/site_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_site_group Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/facilities/#site-groups:\n  Like regions, site groups can be arranged in a recursive hierarchy for grouping sites. However, whereas regions are intended for geographic organization, site groups may be used for functional grouping. For example, you might classify sites as corporate, branch, or customer sites in addition to where they are physically located.\n  The use of both regions and site groups affords to independent but complementary dimensions across which sites can be organized.\n---\n\n# netbox_site_group (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/facilities/#site-groups):\n\n> Like regions, site groups can be arranged in a recursive hierarchy for grouping sites. However, whereas regions are intended for geographic organization, site groups may be used for functional grouping. For example, you might classify sites as corporate, branch, or customer sites in addition to where they are physically located.\n>\n> The use of both regions and site groups affords to independent but complementary dimensions across which sites can be organized.\n\n## Example Usage\n\n```terraform\nresource \"netbox_site_group\" \"parent\" {\n  name        = \"parent\"\n  description = \"sample description\"\n}\n\nresource \"netbox_site_group\" \"child\" {\n  name        = \"child\"\n  description = \"sample description\"\n\n  parent_id = netbox_site_group.parent.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `parent_id` (Number)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/tag.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_tag Resource - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/extras/tag/:\n  > Tags are user-defined labels which can be applied to a variety of objects within NetBox. They can be used to establish dimensions of organization beyond the relationships built into NetBox. For example, you might create a tag to identify a particular ownership or condition across several types of objects.\n  >\n  > Each tag has a label, color, and a URL-friendly slug. For example, the slug for a tag named \"Dunder Mifflin, Inc.\" would be dunder-mifflin-inc. The slug is generated automatically and makes tags easier to work with as URL parameters. Each tag can also be assigned a description indicating its purpose.\n---\n\n# netbox_tag (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/extras/tag/):\n> Tags are user-defined labels which can be applied to a variety of objects within NetBox. They can be used to establish dimensions of organization beyond the relationships built into NetBox. For example, you might create a tag to identify a particular ownership or condition across several types of objects.\n>\n> Each tag has a label, color, and a URL-friendly slug. For example, the slug for a tag named \"Dunder Mifflin, Inc.\" would be dunder-mifflin-inc. The slug is generated automatically and makes tags easier to work with as URL parameters. Each tag can also be assigned a description indicating its purpose.\n\n## Example Usage\n\n```terraform\nresource \"netbox_tag\" \"dmz\" {\n  name      = \"DMZ\"\n  color_hex = \"ff00ff\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `color_hex` (String) Defaults to `9e9e9e`.\n- `description` (String)\n- `slug` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/tenant.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_tenant Resource - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/tenancy/#tenants:\n  A tenant represents a discrete grouping of resources used for administrative purposes. Typically, tenants are used to represent individual customers or internal departments within an organization.\n  Tenant assignment is used to signify the ownership of an object in NetBox. As such, each object may only be owned by a single tenant. For example, if you have a firewall dedicated to a particular customer, you would assign it to the tenant which represents that customer. However, if the firewall serves multiple customers, it doesn't belong to any particular customer, so tenant assignment would not be appropriate.\n---\n\n# netbox_tenant (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/tenancy/#tenants):\n\n> A tenant represents a discrete grouping of resources used for administrative purposes. Typically, tenants are used to represent individual customers or internal departments within an organization.\n>\n> Tenant assignment is used to signify the ownership of an object in NetBox. As such, each object may only be owned by a single tenant. For example, if you have a firewall dedicated to a particular customer, you would assign it to the tenant which represents that customer. However, if the firewall serves multiple customers, it doesn't belong to any particular customer, so tenant assignment would not be appropriate.\n\n## Example Usage\n\n```terraform\nresource \"netbox_tenant\" \"customer_a\" {\n  name = \"Customer A\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `group_id` (Number)\n- `slug` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/tenant_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_tenant_group Resource - terraform-provider-netbox\"\nsubcategory: \"Tenancy\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/tenancy/#tenant-groups:\n  Tenants can be organized by custom groups. For instance, you might create one group called \"Customers\" and one called \"Departments.\" The assignment of a tenant to a group is optional.\n  Tenant groups may be nested recursively to achieve a multi-level hierarchy. For example, you might have a group called \"Customers\" containing subgroups of individual tenants grouped by product or account team.\n---\n\n# netbox_tenant_group (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/tenancy/#tenant-groups):\n\n> Tenants can be organized by custom groups. For instance, you might create one group called \"Customers\" and one called \"Departments.\" The assignment of a tenant to a group is optional.\n>\n> Tenant groups may be nested recursively to achieve a multi-level hierarchy. For example, you might have a group called \"Customers\" containing subgroups of individual tenants grouped by product or account team.\n\n## Example Usage\n\n```terraform\nresource \"netbox_tenant_group\" \"test\" {\n  name = \"test-tenant-group\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `parent_id` (Number)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/token.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_token Resource - terraform-provider-netbox\"\nsubcategory: \"Authentication\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/rest-api/authentication/#tokens:\n  A token is a unique identifier mapped to a NetBox user account. Each user may have one or more tokens which he or she can use for authentication when making REST API requests. To create a token, navigate to the API tokens page under your user profile.\n---\n\n# netbox_token (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/rest-api/authentication/#tokens):\n\n> A token is a unique identifier mapped to a NetBox user account. Each user may have one or more tokens which he or she can use for authentication when making REST API requests. To create a token, navigate to the API tokens page under your user profile.\n\n## Example Usage\n\n```terraform\nresource \"netbox_user\" \"test\" {\n  username = \"johndoe\"\n  password = \"Abcdefghijkl1\"\n}\n\nresource \"netbox_token\" \"test_basic\" {\n  user_id       = netbox_user.test.id\n  key           = \"0123456789012345678901234567890123456789\"\n  allowed_ips   = [\"2.4.8.16/32\"]\n  write_enabled = false\n  expires       = \"2036-01-02T15:04:05.000Z\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `user_id` (Number)\n\n### Optional\n\n- `allowed_ips` (List of String)\n- `description` (String)\n- `expires` (String)\n- `key` (String, Sensitive)\n- `write_enabled` (Boolean)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `last_used` (String)\n\n\n"
  },
  {
    "path": "docs/resources/user.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_user Resource - terraform-provider-netbox\"\nsubcategory: \"Authentication\"\ndescription: |-\n  This resource is used to manage users.\n---\n\n# netbox_user (Resource)\n\nThis resource is used to manage users.\n\n## Example Usage\n\n```terraform\nresource \"netbox_user\" \"test\" {\n  username = \"johndoe\"\n  password = \"Abcdefghijkl1\"\n  active   = true\n  staff    = true\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `password` (String, Sensitive)\n- `username` (String)\n\n### Optional\n\n- `active` (Boolean) Defaults to `true`.\n- `email` (String) Defaults to `\"\"`.\n- `first_name` (String) Defaults to `\"\"`.\n- `group_ids` (Set of Number)\n- `last_name` (String) Defaults to `\"\"`.\n- `staff` (Boolean) Defaults to `false`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/virtual_chassis.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_virtual_chassis Resource - terraform-provider-netbox\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/devices-cabling/#virtual-chassis:\n      > Sometimes it is necessary to model a set of physical devices as sharing a single management plane. Perhaps the most common example of such a scenario is stackable switches. These can be modeled as virtual chassis in NetBox, with one device acting as the chassis master and the rest as members. All components of member devices will appear on the master.\n---\n\n# netbox_virtual_chassis (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/devices-cabling/#virtual-chassis):\n\n\t\t> Sometimes it is necessary to model a set of physical devices as sharing a single management plane. Perhaps the most common example of such a scenario is stackable switches. These can be modeled as virtual chassis in NetBox, with one device acting as the chassis master and the rest as members. All components of member devices will appear on the master.\n\n## Example Usage\n\n```terraform\nresource \"netbox_virtual_chassis\" \"example\" {\n  name        = \"chassis\"\n  domain      = \"domain\"\n  description = \"virtual chassis\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `domain` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/virtual_disk.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_virtual_disk Resource - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/models/virtualization/virtualdisk/:\n      > A virtual disk is used to model discrete virtual hard disks assigned to virtual machines.\n---\n\n# netbox_virtual_disk (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/models/virtualization/virtualdisk/):\n\n\t\t> A virtual disk is used to model discrete virtual hard disks assigned to virtual machines.\n\n## Example Usage\n\n```terraform\n// Assumes vmw-cluster-01 exists in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\nresource \"netbox_virtual_machine\" \"base_vm\" {\n  cluster_id = data.netbox_cluster.vmw_cluster_01.id\n  name       = \"myvm-1\"\n}\n\nresource \"netbox_virtual_disk\" \"example\" {\n  name               = \"disk-01\"\n  description        = \"Main disk\"\n  size_mb            = 50\n  virtual_machine_id = netbox_virtual_machine.base_vm.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `size_mb` (Number)\n- `virtual_machine_id` (Number)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/virtual_machine.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_virtual_machine Resource - terraform-provider-netbox\"\nsubcategory: \"Virtualization\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#virtual-machines:\n  A virtual machine is a virtualized compute instance. These behave in NetBox very similarly to device objects, but without any physical attributes. For example, a VM may have interfaces assigned to it with IP addresses and VLANs, however its interfaces cannot be connected via cables (because they are virtual). Each VM may also define its compute, memory, and storage resources as well.\n---\n\n# netbox_virtual_machine (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#virtual-machines):\n\n> A virtual machine is a virtualized compute instance. These behave in NetBox very similarly to device objects, but without any physical attributes. For example, a VM may have interfaces assigned to it with IP addresses and VLANs, however its interfaces cannot be connected via cables (because they are virtual). Each VM may also define its compute, memory, and storage resources as well.\n\n## Example Usage\n\n```terraform\n// Assumes vmw-cluster-01 exists in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\nresource \"netbox_virtual_machine\" \"base_vm\" {\n  cluster_id = data.netbox_cluster.vmw_cluster_01.id\n  name       = \"myvm-1\"\n}\n// Assumes vmw-cluster-01 exists in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\nresource \"netbox_virtual_machine\" \"basic_vm\" {\n  cluster_id   = data.netbox_cluster.vmw_cluster_01.id\n  name         = \"myvm-2\"\n  disk_size_mb = 40000\n  memory_mb    = 4092\n  vcpus        = \"2\"\n}\n// Assumes vmw-cluster-01 exists as a cluster in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\n// Assumes customer-a exists as a tenant in Netbox\ndata \"netbox_tenant\" \"customer_a\" {\n  name = \"Customer A\"\n}\n\nresource \"netbox_virtual_machine\" \"full_vm\" {\n  cluster_id   = data.netbox_cluster.vmw_cluster_01.id\n  name         = \"myvm-3\"\n  disk_size_mb = 40000\n  memory_mb    = 4092\n  vcpus        = \"2\"\n  role_id      = 31 // This corresponds to the Netbox ID for a given role\n  tenant_id    = data.netbox_tenant.customer_a.id\n  local_context_data = jsonencode({\n    \"setting_a\" = \"Some Setting\"\n    \"setting_b\" = 42\n  })\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `cluster_id` (Number) At least one of `site_id` or `cluster_id` must be given.\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `device_id` (Number)\n- `disk_size_mb` (Number) The disk size in MB. When virtual disks are attached to this VM, NetBox automatically computes this as the aggregate of those disks and rejects manual values. In that case, omit this field from the configuration and let it be computed.\n- `local_context_data` (String) This is best managed through the use of `jsonencode` and a map of settings.\n- `memory_mb` (Number)\n- `platform_id` (Number)\n- `role_id` (Number)\n- `site_id` (Number) At least one of `site_id` or `cluster_id` must be given.\n- `status` (String) Valid values are `offline`, `active`, `planned`, `staged`, `failed` and `decommissioning`. Defaults to `active`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `vcpus` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `primary_ipv4` (Number)\n- `primary_ipv6` (Number)\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/vlan.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vlan Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/vlans/#vlans:\n  A VLAN represents an isolated layer two domain, identified by a name and a numeric ID (1-4094) as defined in IEEE 802.1Q. VLANs are arranged into VLAN groups to define scope and to enforce uniqueness.\n---\n\n# netbox_vlan (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/vlans/#vlans):\n\n> A VLAN represents an isolated layer two domain, identified by a name and a numeric ID (1-4094) as defined in IEEE 802.1Q. VLANs are arranged into VLAN groups to define scope and to enforce uniqueness.\n\n## Example Usage\n\n```terraform\nresource \"netbox_vlan\" \"example1\" {\n  name = \"VLAN 1\"\n  vid  = 1777\n  tags = []\n}\n\n# Assume netbox_tenant, netbox_site, and netbox_tag resources exist\nresource \"netbox_vlan\" \"example2\" {\n  name        = \"VLAN 2\"\n  vid         = 1778\n  status      = \"reserved\"\n  description = \"Reserved example VLAN\"\n  tenant_id   = netbox_tenant.ex.id\n  site_id     = netbox_site.ex.id\n  group_id    = netbox_vlan_group.ex.id\n  tags        = [netbox_tag.ex.name]\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `vid` (Number)\n\n### Optional\n\n- `description` (String) Defaults to `\"\"`.\n- `group_id` (Number)\n- `role_id` (Number)\n- `site_id` (Number)\n- `status` (String) Valid values are `active`, `reserved` and `deprecated`. Defaults to `active`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/vlan_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vlan_group Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  A VLAN Group represents a collection of VLANs. Generally, these are limited by one of a number of scopes such as \"Site\" or \"Virtualization Cluster\".\n---\n\n# netbox_vlan_group (Resource)\n\n> A VLAN Group represents a collection of VLANs. Generally, these are limited by one of a number of scopes such as \"Site\" or \"Virtualization Cluster\".\n\n## Example Usage\n\n```terraform\n#Basic VLAN Group example\nresource \"netbox_vlan_group\" \"example1\" {\n  name = \"example1\"\n  slug = \"example1\"\n}\n\n#Full VLAN Group example\nresource \"netbox_vlan_group\" \"example2\" {\n  name        = \"Second Example\"\n  slug        = \"example2\"\n  scope_type  = \"dcim.site\"\n  scope_id    = netbox_site.example.id\n  description = \"Second Example VLAN Group\"\n  tags        = [netbox_tag.example.id]\n  vid_ranges  = [[1, 2], [3, 4]]\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `slug` (String)\n- `vid_ranges` (List of List of Number)\n\n### Optional\n\n- `description` (String) Defaults to `\"\"`.\n- `scope_id` (Number) Required when `scope_type` is set.\n- `scope_type` (String) Valid values are `dcim.location`, `dcim.site`, `dcim.sitegroup`, `dcim.region`, `dcim.rack`, `virtualization.cluster` and `virtualization.clustergroup`.\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/vpn_tunnel.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vpn_tunnel Resource - terraform-provider-netbox\"\nsubcategory: \"VPN Tunnels\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/vpn-tunnels/:\n  NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.\n---\n\n# netbox_vpn_tunnel (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/vpn-tunnels/):\n\n> NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.\n\n## Example Usage\n\n```terraform\nresource \"netbox_vpn_tunnel_group\" \"test\" {\n  name = \"my-tunnel-group\"\n}\n\nresource \"netbox_vpn_tunnel\" \"test\" {\n  name            = \"my-tunnel\"\n  encapsulation   = \"ipsec-transport\"\n  status          = \"active\"\n  tunnel_group_id = netbox_vpn_tunnel_group.test.id\n\n  description = \"This is a description.\"\n  tunnel_id   = 3\n  tenant_id   = 2\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `encapsulation` (String) Valid values are `ipsec-transport`, `ipsec-tunnel`, `ip-ip` and `gre`.\n- `name` (String)\n- `status` (String) Valid values are `planned`, `active` and `disabled`.\n- `tunnel_group_id` (Number)\n\n### Optional\n\n- `description` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `tunnel_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/vpn_tunnel_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vpn_tunnel_group Resource - terraform-provider-netbox\"\nsubcategory: \"VPN Tunnels\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/vpn-tunnels/:\n  NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.\n---\n\n# netbox_vpn_tunnel_group (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/vpn-tunnels/):\n\n> NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.\n\n## Example Usage\n\n```terraform\nresource \"netbox_vpn_tunnel_group\" \"test\" {\n  name = \"my-tunnel-group\"\n\n  description = \"My description\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `slug` (String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/vpn_tunnel_termination.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vpn_tunnel_termination Resource - terraform-provider-netbox\"\nsubcategory: \"VPN Tunnels\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/vpn-tunnels/:\n  NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.\n---\n\n# netbox_vpn_tunnel_termination (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/vpn-tunnels/):\n\n> NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.\n\n## Example Usage\n\n```terraform\nresource \"netbox_vpn_tunnel_group\" \"test\" {\n  name        = \"my-tunnel-group\"\n  description = \"description\"\n}\n\nresource \"netbox_vpn_tunnel\" \"test\" {\n  name            = \"my-tunnel\"\n  encapsulation   = \"ipsec-transport\"\n  status          = \"active\"\n  tunnel_group_id = netbox_vpn_tunnel_group.test.id\n}\n\nresource \"netbox_vpn_tunnel_termination\" \"device\" {\n  role                = \"peer\"\n  tunnel_id           = netbox_vpn_tunnel.test.id\n  device_interface_id = 123\n}\n\nresource \"netbox_vpn_tunnel_termination\" \"vm\" {\n  role                         = \"peer\"\n  tunnel_id                    = netbox_vpn_tunnel.test.id\n  virtual_machine_interface_id = 234\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `role` (String) Valid values are `peer`, `hub` and `spoke`.\n- `tunnel_id` (Number)\n\n### Optional\n\n- `device_interface_id` (Number) Exactly one of `virtual_machine_interface_id` or `device_interface_id` must be given.\n- `outside_ip_address_id` (Number)\n- `tags` (Set of String)\n- `virtual_machine_interface_id` (Number) Exactly one of `virtual_machine_interface_id` or `device_interface_id` must be given.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/vrf.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_vrf Resource - terraform-provider-netbox\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#virtual-routing-and-forwarding-vrf:\n  A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space). Each VRF may be assigned to a specific tenant to aid in organizing the available IP space by customer or internal user.\n---\n\n# netbox_vrf (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#virtual-routing-and-forwarding-vrf):\n\n> A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space). Each VRF may be assigned to a specific tenant to aid in organizing the available IP space by customer or internal user.\n\n## Example Usage\n\n```terraform\nresource \"netbox_vrf\" \"cust_a_prod\" {\n  name = \"cust-a-prod\"\n  tags = [\"customer-a\", \"prod\"]\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `description` (String)\n- `enforce_unique` (Boolean) Defaults to `true`.\n- `rd` (String)\n- `tags` (Set of String)\n- `tenant_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/webhook.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_webhook Resource - terraform-provider-netbox\"\nsubcategory: \"Extras\"\ndescription: |-\n  From the official documentation https://docs.netbox.dev/en/stable/integrations/webhooks/:\n  A webhook is a mechanism for conveying to some external system a change that took place in NetBox. For example, you may want to notify a monitoring system whenever the status of a device is updated in NetBox. This can be done by creating a webhook for the device model in NetBox and identifying the webhook receiver. When NetBox detects a change to a device, an HTTP request containing the details of the change and who made it be sent to the specified receiver.\n---\n\n# netbox_webhook (Resource)\n\nFrom the [official documentation](https://docs.netbox.dev/en/stable/integrations/webhooks/):\n\n> A webhook is a mechanism for conveying to some external system a change that took place in NetBox. For example, you may want to notify a monitoring system whenever the status of a device is updated in NetBox. This can be done by creating a webhook for the device model in NetBox and identifying the webhook receiver. When NetBox detects a change to a device, an HTTP request containing the details of the change and who made it be sent to the specified receiver.\n\n## Example Usage\n\n```terraform\nresource \"netbox_webhook\" \"test\" {\n  name         = \"test\"\n  payload_url  = \"https://example.com/webhook\"\n  bodytemplate = \"Sample body\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n- `payload_url` (String)\n\n### Optional\n\n- `additional_headers` (String)\n- `body_template` (String)\n- `ca_file_path` (String)\n- `http_content_type` (String) The complete list of official content types is available [here](https://www.iana.org/assignments/media-types/media-types.xhtml). Defaults to `application/json`.\n- `http_method` (String) Valid values are `GET`, `POST`, `PUT`, `PATCH` and `DELETE`. Defaults to `POST`.\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n\n\n"
  },
  {
    "path": "docs/resources/wireless_lan.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_wireless_lan Resource - terraform-provider-netbox\"\nsubcategory: \"Wireless\"\ndescription: |-\n  A Wireless LAN represents a broadcast wireless network, identified by its SSID and optional authentication settings.\n---\n\n# netbox_wireless_lan (Resource)\n\n> A Wireless LAN represents a broadcast wireless network, identified by its SSID and optional authentication settings.\n\n## Example Usage\n\n```terraform\nresource \"netbox_wireless_lan\" \"guest\" {\n  ssid   = \"guest-wifi\"\n  status = \"active\"\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `ssid` (String)\n\n### Optional\n\n- `auth_cipher` (String) Valid values are `auto`, `tkip` and `aes`.\n- `auth_psk` (String, Sensitive)\n- `auth_type` (String) Valid values are `open`, `wep`, `wpa-personal` and `wpa-enterprise`.\n- `comments` (String)\n- `custom_fields` (Map of String)\n- `description` (String)\n- `group_id` (Number)\n- `status` (String) Valid values are `active`, `reserved`, `disabled` and `deprecated`. Defaults to `active`.\n- `tags` (Set of String)\n- `tenant_id` (Number)\n- `vlan_id` (Number)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "docs/resources/wireless_lan_group.md",
    "content": "---\n# generated by https://github.com/fbreckle/terraform-plugin-docs\npage_title: \"netbox_wireless_lan_group Resource - terraform-provider-netbox\"\nsubcategory: \"Wireless\"\ndescription: |-\n  A Wireless LAN Group is used to organize wireless LANs into a recursive hierarchy.\n---\n\n# netbox_wireless_lan_group (Resource)\n\n> A Wireless LAN Group is used to organize wireless LANs into a recursive hierarchy.\n\n## Example Usage\n\n```terraform\nresource \"netbox_wireless_lan_group\" \"parent\" {\n  name = \"campus\"\n}\n\nresource \"netbox_wireless_lan_group\" \"child\" {\n  name      = \"building-a\"\n  parent_id = netbox_wireless_lan_group.parent.id\n}\n```\n\n<!-- schema generated by tfplugindocs -->\n## Schema\n\n### Required\n\n- `name` (String)\n\n### Optional\n\n- `custom_fields` (Map of String)\n- `description` (String)\n- `parent_id` (Number)\n- `slug` (String)\n- `tags` (Set of String)\n\n### Read-Only\n\n- `id` (String) The ID of this resource.\n- `tags_all` (Set of String)\n\n\n"
  },
  {
    "path": "example/README.md",
    "content": "# example\n\nThis folder is not actively maintained, but can be used for local testing and as a small reference for using this provider.\n"
  },
  {
    "path": "example/main.tf",
    "content": "terraform {\n  required_providers {\n    netbox = {\n      source = \"e-breuninger/netbox\"\n    }\n  }\n}\n\n# example provider configuration for a local netbox deployment\n# e.g. https://github.com/netbox-community/netbox-docker\n#provider \"netbox\" {\n#  server_url = \"http://localhost:8000\"\n#  api_token  = \"0123456789abcdef0123456789abcdef01234567\"\n#}\n\n# example provider configuration for https://netboxdemo.om\nprovider \"netbox\" {\n  server_url = \"https://demo.netbox.dev\"\n  api_token  = \"<your api token>\"\n}\n\nresource \"netbox_tag\" \"foo\" {\n  name      = \"foo\"\n  color_hex = \"00ff00\" # green\n}\n\nresource \"netbox_tag\" \"bar\" {\n  name = \"bar\"\n}\n\nresource \"netbox_device_role\" \"testdevicerole\" {\n  name      = \"my-device-role\"\n  vm_role   = true\n  color_hex = \"ff0000\"\n}\n\nresource \"netbox_site\" \"testsite\" {\n  name   = \"my-test-site\"\n  status = \"active\"\n}\n\nresource \"netbox_platform\" \"testplatform\" {\n  name = \"my-test-platform\"\n}\n\nresource \"netbox_cluster_type\" \"testclustertype\" {\n  name = \"my-test-cluster-type\"\n}\n\nresource \"netbox_cluster_group\" \"testclustergroup\" {\n  name        = \"my-test-cluster-group\"\n  description = \"test cluster group description\"\n}\n\nresource \"netbox_vrf\" \"testvrf\" {\n  name = \"my-test-vrf\"\n}\n\nresource \"netbox_cluster\" \"testcluster\" {\n  name             = \"my-test-cluster\"\n  cluster_type_id  = netbox_cluster_type.testclustertype.id\n  cluster_group_id = netbox_cluster_group.testclustergroup.id\n  site_id          = netbox_site.testsite.id\n\n  # tags can be referenced by name but have to be created first ..\n  tags = [\"foo\"]\n  # .. or explicitly depended upon, unless created separately\n  depends_on = [netbox_tag.foo]\n}\n\nresource \"netbox_tenant\" \"testtenant\" {\n  name = \"my-test-tenant\"\n}\n\nresource \"netbox_virtual_machine\" \"testvm\" {\n  name         = \"my-test-vm\"\n  comments     = \"my-test-comment\"\n  memory_mb    = 1024\n  vcpus        = 4\n  disk_size_mb = 512\n  cluster_id   = netbox_cluster.testcluster.id\n  tenant_id    = netbox_tenant.testtenant.id\n  platform_id  = netbox_platform.testplatform.id\n  role_id      = netbox_device_role.testdevicerole.id\n  tags         = [netbox_tag.foo.name, netbox_tag.bar.name]\n}\n\nresource \"netbox_interface\" \"testinterface\" {\n  virtual_machine_id = netbox_virtual_machine.testvm.id\n  name               = \"my-test-interface\"\n  description        = \"description\"\n\n  tags = [netbox_tag.foo.name]\n}\n\nresource \"netbox_ip_address\" \"testip\" {\n  ip_address   = \"1.2.3.4/32\"\n  dns_name     = \"test.example.com\"\n  interface_id = netbox_interface.testinterface.id\n  status       = \"active\"\n  tenant_id    = netbox_tenant.testtenant.id\n  vrf_id       = netbox_vrf.testvrf.id\n\n  tags = [netbox_tag.foo.name]\n}\n\nresource \"netbox_primary_ip\" \"testprimaryip\" {\n  virtual_machine_id = netbox_virtual_machine.testvm.id\n  ip_address_id      = netbox_ip_address.testip.id\n}\n\nresource \"netbox_service\" \"testservice\" {\n  name               = \"my-test-service\"\n  virtual_machine_id = netbox_virtual_machine.testvm.id\n  protocol           = \"tcp\"\n  ports              = [80]\n}\n\nresource \"netbox_webhook\" \"testwebhook\" {\n  name          = \"My Webhook\"\n  enabled       = \"true\"\n  type_create   = \"true\"\n  payload_url   = \"https://example.com/webhook\"\n  content_types = \"dcim.site\"\n  body_template = \"Sample Body\"\n}\n\nresource \"netbox_config_context\" \"test\" {\n  name = \"My Config Context\"\n  data = jsonencode(\n    { \"testkey\" = \"testval\" }\n  )\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_asn/data-source.tf",
    "content": "data \"netbox_asn\" \"asn_1\" {\n  asn = \"1111\"\n  tag = \"tag-1\"\n}\n\ndata \"netbox_asn\" \"asn_2\" {\n  tag    = \"tag-1\"\n  tag__n = \"tag-2\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_asns/data-source.tf",
    "content": "data \"netbox_asns\" \"asns\" {\n  filter {\n    name  = \"asn__gte\"\n    value = \"1000\"\n  }\n  filter {\n    name  = \"asn__lte\"\n    value = \"2000\"\n  }\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_cluster/data-source.tf",
    "content": "data \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_cluster_group/data-source.tf",
    "content": "data \"netbox_cluster_group\" \"dc_west\" {\n  name = \"dc-west\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_clusters/data-source.tf",
    "content": "// Get all clusters of a specific type\ndata \"netbox_cluster_type\" \"vmware\" {\n  name = \"VMware ESXi\"\n}\n\ndata \"netbox_clusters\" \"vmware_clusters\" {\n  filter {\n    name  = \"cluster_type_id\"\n    value = data.netbox_cluster_type.vmware.id\n  }\n}\n\n// Get clusters by name regex\ndata \"netbox_clusters\" \"prod_clusters\" {\n  name_regex = \"prod-.*\"\n}\n\n// Get clusters at a specific site\ndata \"netbox_clusters\" \"site_clusters\" {\n  filter {\n    name  = \"site_id\"\n    value = data.netbox_site.main.id\n  }\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_device_render_config/data-source.tf",
    "content": "# Get the rendered configuration for a device\ndata \"netbox_device_render_config\" \"server_config\" {\n  device_id = 60\n}\n\n# Use the rendered configuration\noutput \"rendered_config\" {\n  value = data.netbox_device_render_config.server_config.content\n}\n\noutput \"template_used\" {\n  value = data.netbox_device_render_config.server_config.config_template_name\n}\n\n# Example: Write the config to a file using local_file resource\n# resource \"local_file\" \"kickstart\" {\n#   content  = data.netbox_device_render_config.server_config.content\n#   filename = \"${path.module}/kickstart.cfg\"\n# }\n"
  },
  {
    "path": "examples/data-sources/netbox_device_role/data-source.tf",
    "content": "data \"netbox_device_role\" \"core_sw\" {\n  name = \"core-sw\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_device_type/data-source.tf",
    "content": "# Get device type by model name\ndata \"netbox_device_type\" \"ex1\" {\n  model = \"7210 SAS-Sx 10/100GE\"\n}\n\n# Get device type by slug\ndata \"netbox_device_type\" \"ex2\" {\n  slug = \"7210-sas-sx-10-100GE\"\n}\n\n# Get device type by manufacturer and part number information\ndata \"netbox_device_type\" \"ex3\" {\n  manufacturer = \"Nokia\"\n  part_number  = \"3HE11597AARB01\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_interfaces/data-source.tf",
    "content": "data \"netbox_interfaces\" \"myvm_eth0\" {\n  name_regex = \"eth0\"\n  filter {\n    name  = \"name\"\n    value = \"myvm\"\n  }\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_ip_address/data-source.tf",
    "content": "data \"netbox_ip_address\" \"ip_address\" {\n  id = 1001\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_ip_range/data-source.tf",
    "content": "data \"netbox_ip_range\" \"cust_a_prod\" {\n  contains = \"10.0.0.1/24\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_platform/data-source.tf",
    "content": "data \"netbox_platform\" \"PANOS\" {\n  name = \"PANOS\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_rir/data-source.tf",
    "content": "data \"netbox_rir\" \"rir_1\" {\n  name = \"ARIN\"\n}\n\ndata \"netbox_rir\" \"rir_2\" {\n  slug = \"arin\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_site/data-source.tf",
    "content": "data \"netbox_site\" \"get_by_name\" {\n  name = \"Example Site 1\"\n}\n\ndata \"netbox_site\" \"get_by_slug\" {\n  slug = \"example-site-1\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_site_group/data-source.tf",
    "content": "// Assumes the corresponding site groups exist\ndata \"netbox_site_group\" \"get_by_name\" {\n  name = \"example-sitegroup-1\"\n}\n\ndata \"netbox_site_group\" \"get_by_slug\" {\n  slug = \"sitegrp\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_tag/data-source.tf",
    "content": "data \"netbox_tag\" \"dmz\" {\n  name = \"DMZ\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_tags/data-source.tf",
    "content": "data \"netbox_tags\" \"all_tags\" {\n}\n\ndata \"netbox_tags\" \"ansible_tags\" {\n  filter {\n    name  = \"name__isw\"\n    value = \"ansible_\"\n  }\n}\n\ndata \"netbox_tags\" \"not_ansible_tags\" {\n  filter {\n    name  = \"name__nisw\"\n    value = \"ansible_\"\n  }\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_tenant/data-source.tf",
    "content": "data \"netbox_tenant\" \"customer_a\" {\n  name = \"Customer A\"\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_virtual_disk/data-source.tf",
    "content": "# Filter by name\ndata \"netbox_virtual_disk\" \"disk_by_name\" {\n  filter {\n    name  = \"name\"\n    value = \"disk1\"\n  }\n}\n\n# Filter by tag\ndata \"netbox_virtual_disk\" \"disk_by_tag\" {\n  filter {\n    name  = \"tag\"\n    value = \"production\"\n  }\n}\n\n# Multiple filters\ndata \"netbox_virtual_disk\" \"disk_filtered\" {\n  filter {\n    name  = \"name\"\n    value = \"disk1\"\n  }\n  filter {\n    name  = \"tag\"\n    value = \"production\"\n  }\n}\n\n# Filter with name regex\ndata \"netbox_virtual_disk\" \"disk_regex\" {\n  name_regex = \"^disk[0-9]+\"\n  limit      = 10\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_virtual_machines/data-source.tf",
    "content": "// Assumes vmw-cluster-01 exists as a cluster in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\ndata \"netbox_virtual_machines\" \"base_vm\" {\n  name_regex = \"myvm-1\"\n  filter {\n    name  = \"cluster_id\"\n    value = data.netbox_cluster.vmw_cluster_01.id\n  }\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_vlan/data-source.tf",
    "content": "# Get VLAN by name\ndata \"netbox_vlan\" \"vlan1\" {\n  name = \"vlan-1\"\n}\n\n# Get VLAN by VID and IPAM role ID\ndata \"netbox_vlan\" \"vlan2\" {\n  vid  = 1234\n  role = netbox_ipam_role.example.id\n}\n\n# Get VLAN by name and tenant ID\ndata \"netbox_vlan\" \"vlan3\" {\n  name   = \"vlan-3\"\n  tenant = netbox_tenant.example.id\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_vlan_group/data-source.tf",
    "content": "# Get VLAN group by name\ndata \"netbox_vlan_group\" \"example1\" {\n  name = \"example1\"\n}\n\n# Get VLAN group by stub\ndata \"netbox_vlan_group\" \"example2\" {\n  slug = \"example2\"\n}\n\n# Get VLAN group by name and scope_type/id\ndata \"netbox_vlan_group\" \"example3\" {\n  name       = \"example\"\n  scope_type = \"dcim.site\"\n  scope_id   = netbox_site.example.id\n}\n"
  },
  {
    "path": "examples/data-sources/netbox_vrf/data-source.tf",
    "content": "data \"netbox_vrf\" \"cust_a_prod\" {\n  name = \"cust-a-prod\"\n}\n"
  },
  {
    "path": "examples/provider/provider.tf",
    "content": "terraform {\n  required_providers {\n    netbox = {\n      source  = \"e-breuninger/netbox\"\n      version = \"~> 3.2.1\"\n    }\n  }\n}\n\n# example provider configuration for https://demo.netbox.dev\nprovider \"netbox\" {\n  server_url = \"https://demo.netbox.dev\"\n  api_token  = \"<your api key>\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_aggregate/resource.tf",
    "content": "resource \"netbox_rir\" \"test\" {\n  name = \"testrir\"\n}\nresource \"netbox_aggregate\" \"test\" {\n  prefix      = \"1.1.1.0/25\"\n  description = \"my description\"\n  rir_id      = netbox_rir.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_asn/resource.tf",
    "content": "resource \"netbox_rir\" \"test\" {\n  name = \"testrir\"\n}\n\nresource \"netbox_asn\" \"test\" {\n  asn         = 1337\n  rir_id      = netbox_rir.test.id\n  description = \"test\"\n  comments    = \"test\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_available_ip_address/assign_to_interface.tf",
    "content": "// Assumes Netbox already has a VM whos name matches 'dc-west-myvm-20'\ndata \"netbox_virtual_machine\" \"myvm\" {\n  name_regex = \"dc-west-myvm-20\"\n}\n\ndata \"netbox_prefix\" \"test\" {\n  cidr = \"10.0.0.0/24\"\n}\n\nresource \"netbox_interface\" \"myvm-eth0\" {\n  name               = \"eth0\"\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n\nresource \"netbox_available_ip_address\" \"myvm-ip\" {\n  prefix_id    = data.netbox_prefix.test.id\n  status       = \"active\"\n  interface_id = netbox_interface.myvm-eth0.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_available_ip_address/prefix.tf",
    "content": "data \"netbox_prefix\" \"test\" {\n  cidr = \"10.0.0.0/24\"\n}\n\nresource \"netbox_available_ip_address\" \"test\" {\n  prefix_id = data.netbox_prefix.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_available_ip_address/range.tf",
    "content": "data \"netbox_ip_range\" \"test\" {\n  start_address = \"10.0.0.1/24\"\n  end_address   = \"10.0.0.50/24\"\n}\n\nresource \"netbox_available_ip_address\" \"test\" {\n  ip_range_id = data.netbox_ip_range.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_available_prefix/resource.tf",
    "content": "data \"netbox_prefix\" \"test\" {\n  cidr = \"10.0.0.0/24\"\n}\n\nresource \"netbox_available_prefix\" \"test\" {\n  parent_prefix_id = data.netbox_prefix.test.id\n  prefix_length    = 25\n  status           = \"active\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_available_vlan/multiple.tf",
    "content": "resource \"netbox_site\" \"testSite\" {\n  name = \"test site\"\n  slug = \"test-site\"\n}\n\nresource \"netbox_vlan_group\" \"group1\" {\n  name        = \"Group One\"\n  slug        = \"group-one\"\n  scope_id    = netbox_site.testSite.id\n  scope_type  = \"dcim.site\"\n  description = \"First VLAN group\"\n  vid_ranges  = [[1, 2], [7, 17]]\n}\n\nresource \"netbox_available_vlan\" \"vlan1\" {\n  name        = \"vlan1\"\n  status      = \"active\"\n  description = \"Virtual network for team 1\"\n  group_id    = netbox_vlan_group.group1.id\n  site_id     = netbox_vlan_group.group1.scope_id\n}\n\nresource \"netbox_available_vlan\" \"vlan2\" {\n  name        = \"vlan2\"\n  status      = \"active\"\n  description = \"Virtual network for team 2\"\n  group_id    = netbox_vlan_group.group1.id\n  site_id     = netbox_vlan_group.group1.scope_id\n}\n\nresource \"netbox_available_vlan\" \"vlan3\" {\n  name        = \"vlan3\"\n  status      = \"active\"\n  description = \"Virtual network for team 3\"\n  group_id    = netbox_vlan_group.group1.id\n  site_id     = netbox_vlan_group.group1.scope_id\n}\n"
  },
  {
    "path": "examples/resources/netbox_available_vlan/prefix.tf",
    "content": "resource \"netbox_site\" \"testSite\" {\n  name = \"test site\"\n  slug = \"test-site\"\n}\n\nresource \"netbox_vlan_group\" \"testGroup\" {\n  name        = \"Group One\"\n  slug        = \"group-one\"\n  scope_id    = netbox_site.testSite.id\n  scope_type  = \"dcim.site\"\n  description = \"First VLAN group\"\n  vid_ranges  = [[1, 20]]\n}\n\nresource \"netbox_available_vlan\" \"testVlan\" {\n  name        = \"test-vlan\"\n  status      = \"active\"\n  description = \"Virtual network for testing purposes\"\n  group_id    = netbox_vlan_group.testGroup.id\n  site_id     = netbox_vlan_group.testGroup.scope_id\n}\n\nresource \"netbox_prefix\" \"testPrefix\" {\n  prefix      = \"192.168.40.0/24\"\n  status      = \"active\"\n  description = \"test prefix\"\n  site_id     = netbox_site.testSite.id\n  vlan_id     = netbox_available_vlan.testVlan.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_available_vlan/range.tf",
    "content": "resource \"netbox_site\" \"testSite\" {\n  name = \"test site\"\n  slug = \"test-site\"\n}\n\nresource \"netbox_vlan_group\" \"testGroup\" {\n  name        = \"Group One\"\n  slug        = \"group-one\"\n  scope_id    = netbox_site.testSite.id\n  scope_type  = \"dcim.site\"\n  description = \"First VLAN group\"\n  vid_ranges  = [[1, 2], [7, 17]]\n}\n\nresource \"netbox_available_vlan\" \"testVlan\" {\n  name        = \"test-vlan\"\n  status      = \"active\"\n  description = \"Virtual network for testing purposes\"\n  group_id    = netbox_vlan_group.testGroup.id\n  site_id     = netbox_vlan_group.testGroup.scope_id\n}\n\nresource \"netbox_available_vlan\" \"testVlan2\" {\n  name        = \"test-vlan2\"\n  status      = \"active\"\n  description = \"Virtual network for testing purposes\"\n  group_id    = netbox_vlan_group.testGroup.id\n  site_id     = netbox_vlan_group.testGroup.scope_id\n}\n\nresource \"netbox_available_vlan\" \"testVlan3\" {\n  name        = \"test-vlan3\"\n  status      = \"active\"\n  description = \"Virtual network for testing purposes\"\n  group_id    = netbox_vlan_group.testGroup.id\n  site_id     = netbox_vlan_group.testGroup.scope_id\n}\n"
  },
  {
    "path": "examples/resources/netbox_available_vlan/site.tf",
    "content": "resource \"netbox_site\" \"testSite\" {\n  name = \"test site\"\n  slug = \"test-site\"\n}\n\nresource \"netbox_vlan_group\" \"testGroup\" {\n  name        = \"Group One\"\n  slug        = \"group-one\"\n  scope_id    = netbox_site.testSite.id\n  scope_type  = \"dcim.site\"\n  description = \"First VLAN group\"\n  vid_ranges  = [[1, 20]]\n}\n\nresource \"netbox_available_vlan\" \"testVlan\" {\n  name        = \"test-vlan\"\n  status      = \"active\"\n  description = \"Virtual network for testing purposes\"\n  group_id    = netbox_vlan_group.testGroup.id\n  site_id     = netbox_vlan_group.testGroup.scope_id\n}\n"
  },
  {
    "path": "examples/resources/netbox_cable/resource.tf",
    "content": "// assumes that the referenced console port resources exist\nresource \"netbox_cable\" \"test\" {\n  a_termination {\n    object_type = \"dcim.consoleserverport\"\n    object_id   = netbox_device_console_server_port.kvm1.id\n  }\n  a_termination {\n    object_type = \"dcim.consoleserverport\"\n    object_id   = netbox_device_console_server_port.kvm2.id\n  }\n\n  b_termination {\n    object_type = \"dcim.consoleport\"\n    object_id   = netbox_device_console_port.server1.id\n  }\n  b_termination {\n    object_type = \"dcim.consoleport\"\n    object_id   = netbox_device_console_port.server2.id\n  }\n\n  status      = \"connected\"\n  label       = \"KVM cable\"\n  type        = \"cat8\"\n  color_hex   = \"123456\"\n  length      = 10\n  length_unit = \"m\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_circuit/resource.tf",
    "content": "resource \"netbox_tenant\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_circuit_provider\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_circuit_type\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_circuit\" \"test\" {\n  cid         = \"test\"\n  status      = \"active\"\n  provider_id = netbox_circuit_provider.test.id\n  type_id     = netbox_circuit_type.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_circuit_provider/resource.tf",
    "content": "resource \"netbox_circuit_provider\" \"test\" {\n  name = \"test\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_circuit_termination/resource.tf",
    "content": "resource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_circuit_provider\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_circuit_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_circuit\" \"test\" {\n  cid         = \"%[1]s\"\n  status      = \"active\"\n  provider_id = netbox_circuit_provider.test.id\n  type_id     = netbox_circuit_type.test.id\n}\n\nresource \"netbox_circuit_termination\" \"test\" {\n  circuit_id     = netbox_circuit.test.id\n  term_side      = \"A\"\n  site_id        = netbox_site.test.id\n  port_speed     = 100000\n  upstream_speed = 50000\n}\n"
  },
  {
    "path": "examples/resources/netbox_circuit_type/resource.tf",
    "content": "resource \"netbox_circuit_type\" \"test\" {\n  name = \"test\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_cluster/resource.tf",
    "content": "// Assumes the 'dc-west' cluster group already exists\ndata \"netbox_cluster_group\" \"dc_west\" {\n  name = \"dc-west\"\n}\n\nresource \"netbox_cluster_type\" \"vmw_vsphere\" {\n  name = \"VMware vSphere 6\"\n}\n\nresource \"netbox_cluster\" \"vmw_cluster_01\" {\n  cluster_type_id  = netbox_cluster_type.vmw_vsphere.id\n  name             = \"vmw-cluster-01\"\n  cluster_group_id = data.netbox_cluster_group.dc_west.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_cluster_group/resource.tf",
    "content": "resource \"netbox_cluster_group\" \"dc_west\" {\n  description = \"West Datacenter Cluster\"\n  name        = \"dc-west\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_cluster_type/resource.tf",
    "content": "resource \"netbox_cluster_type\" \"vmw_vsphere\" {\n  name = \"VMware vSphere 6\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_config_context/resource.tf",
    "content": "resource \"netbox_config_context\" \"test\" {\n  name = \"%s\"\n  data = jsonencode({ \"testkey\" = \"testval\" })\n}\n"
  },
  {
    "path": "examples/resources/netbox_config_template/resource.tf",
    "content": "resource \"netbox_config_template\" \"test\" {\n  name               = \"test\"\n  description        = \"test description\"\n  template_code      = \"hostname {{ name }}\"\n  environment_params = jsonencode({ \"name\" = \"my-hostname\" })\n}\n"
  },
  {
    "path": "examples/resources/netbox_contact/resource.tf",
    "content": "resource \"netbox_contact\" \"test\" {\n  name  = \"John Doe\"\n  email = \"test@example.com\"\n  phone = \"123-123123\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_contact_assignment/resource.tf",
    "content": "resource \"netbox_contact\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_contact_role\" \"test\" {\n  name = \"test\"\n}\n\n// Assumes that a device with id 123 exists\nresource \"netbox_contact_assignment\" \"test\" {\n  content_type = \"dcim.device\"\n  object_id    = 123\n  contact_id   = netbox_contact.test.id\n  role_id      = netbox_contact_role.test.id\n  priority     = \"primary\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_contact_group/resource.tf",
    "content": "resource \"netbox_contact_group\" \"test\" {\n  name = \"test\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_contact_role/resource.tf",
    "content": "resource \"netbox_contact_role\" \"test\" {\n  name = \"test\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_custom_field/resource.tf",
    "content": "resource \"netbox_custom_field\" \"test\" {\n  name             = \"test\"\n  type             = \"text\"\n  content_types    = [\"virtualization.vminterface\"]\n  weight           = 100\n  validation_regex = \"^.*$\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_custom_field_choice_set/resource.tf",
    "content": "resource \"netbox_custom_field_choice_set\" \"test\" {\n  name        = \"my-custom-field-set\"\n  description = \"Description\"\n  extra_choices = [\n    [\"choice1\", \"label1\"], # label and choice are different\n    [\"choice2\", \"choice2\"] # label and choice are the same\n  ]\n}\n"
  },
  {
    "path": "examples/resources/netbox_device/resource.tf",
    "content": "resource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name      = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model           = \"test\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n  local_context_data = jsonencode({\n    \"setting_a\" = \"Some Setting\"\n    \"setting_b\" = 42\n  })\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_bay/resource.tf",
    "content": "resource \"netbox_tenant\" \"example\" {\n  name = \"example_tenant\"\n}\n\nresource \"netbox_site\" \"example\" {\n  name   = \"example_site\"\n  status = \"active\"\n}\n\nresource \"netbox_manufacturer\" \"example\" {\n  name = \"example_manufacturer\"\n}\n\nresource \"netbox_device_type\" \"example\" {\n  model           = \"example_device_type\"\n  manufacturer_id = netbox_manufacturer.example.id\n  subdevice_role  = \"parent\"\n}\n\nresource \"netbox_device_type\" \"example_installed\" {\n  model           = \"example_device_type_installed\"\n  manufacturer_id = netbox_manufacturer.example.id\n  u_height        = 0\n  subdevice_role  = \"child\"\n}\n\nresource \"netbox_device_role\" \"example\" {\n  name      = \"example_role\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"example\" {\n  name           = \"example_device\"\n  device_type_id = netbox_device_type.example.id\n  tenant_id      = netbox_tenant.example.id\n  role_id        = netbox_device_role.example.id\n  site_id        = netbox_site.example.id\n}\n\nresource \"netbox_device\" \"example_installed\" {\n  name           = \"example_device_installed\"\n  device_type_id = netbox_device_type.example_installed.id\n  tenant_id      = netbox_tenant.example.id\n  role_id        = netbox_device_role.example.id\n  site_id        = netbox_site.example.id\n}\n\nresource \"netbox_device_bay\" \"example\" {\n  device_id           = netbox_device.example.id\n  name                = \"example_device_bay\"\n  label               = \"example_label\"\n  description         = \"example_description\"\n  installed_device_id = netbox_device.example_installed.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_bay_template/resource.tf",
    "content": "resource \"netbox_manufacturer\" \"example\" {\n  name = \"example_manufacturer\"\n}\n\nresource \"netbox_device_type\" \"example\" {\n  model           = \"example_device_model\"\n  slug            = \"example_device_slug\"\n  part_number     = \"example_part_number\"\n  manufacturer_id = netbox_manufacturer.example.id\n  subdevice_role  = \"parent\"\n}\n\nresource \"netbox_device_bay_template\" \"example\" {\n  name           = \"example_device_bay_template\"\n  device_type_id = netbox_device_type.example.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_console_port/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_console_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"console port\"\n  type           = \"de-9\"\n  speed          = 1200\n  mark_connected = true\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_console_server_port/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_console_server_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"console server port\"\n  type           = \"de-9\"\n  speed          = 1200\n  mark_connected = true\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_front_port/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"rear port 1\"\n  type           = \"8p8c\"\n  positions      = 2\n  mark_connected = true\n}\n\nresource \"netbox_device_front_port\" \"test\" {\n  device_id          = netbox_device.test.id\n  name               = \"front port 1\"\n  type               = \"8p8c\"\n  rear_port_id       = netbox_device_rear_port.test.id\n  rear_port_position = 2\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_interface/resource.tf",
    "content": "// Assumes a device with ID 123 exists\nresource \"netbox_device_interface\" \"test\" {\n  name      = \"testinterface\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_module_bay/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name      = \"module bay 1\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_power_outlet/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_power_outlet\" \"test\" {\n  device_id = netbox_device.test.id\n  name      = \"power outlet\"\n  type      = \"iec-60320-c5\"\n  feed_leg  = \"A\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_power_port/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_power_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"power port\"\n  maximum_draw   = 750\n  allocated_draw = 500\n  type           = \"iec-60320-c6\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_primary_ip/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_ip_address\" \"test_v4\" {\n  ip_address          = \"1.1.1.1/32\"\n  status              = \"active\"\n  device_interface_id = netbox_device_interface.test.id\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4\" {\n  device_id     = netbox_device.test.id\n  ip_address_id = netbox_ip_address.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_rear_port/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"rear port 1\"\n  type           = \"8p8c\"\n  positions      = 2\n  mark_connected = true\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_role/resource.tf",
    "content": "resource \"netbox_device_role\" \"core_sw\" {\n  color_hex = \"ff00ff\"\n  name      = \"core-sw\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_device_type/resource.tf",
    "content": "resource \"netbox_manufacturer\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model           = \"test\"\n  part_number     = \"123\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_event_rule/resource.tf",
    "content": "resource \"netbox_webhook\" \"test\" {\n  name        = \"my-webhook\"\n  payload_url = \"https://example.com/webhook\"\n}\n\nresource \"netbox_event_rule\" \"webhook\" {\n  name             = \"my-event-rule\"\n  content_types    = [\"dcim.site\", \"virtualization.cluster\"]\n  action_type      = \"webhook\"\n  action_object_id = netbox_webhook.test.id\n  event_types = [\n    \"object_created\",\n    \"object_updated\",\n    \"object_deleted\",\n    \"job_started\",\n    \"job_completed\",\n    \"job_failed\",\n    \"job_errored\"\n  ]\n}\n\nresource \"netbox_event_rule\" \"script\" {\n  name             = \"my-script-event-rule\"\n  content_types    = [\"dcim.site\"]\n  action_type      = \"script\"\n  action_object_id = 42 # existing NetBox Script ID\n  event_types      = [\"object_created\"]\n}\n"
  },
  {
    "path": "examples/resources/netbox_group/resource.tf",
    "content": "resource \"netbox_group\" \"test\" {\n  name = \"test-group\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_interface/resource.tf",
    "content": "// Assume Netbox already has a VM whos name matches 'dc-west-myvm-20'\ndata \"netbox_virtual_machine\" \"myvm\" {\n  name_regex = \"dc-west-myvm-20\"\n}\n\nresource \"netbox_interface\" \"myvm_eth0\" {\n  name               = \"eth0\"\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n\n// Assume existing VLAN resources 'test1' and 'test2'\nresource \"netbox_interface\" \"myvm_eth1\" {\n  name               = \"eth1\"\n  enabled            = true\n  mac_address        = \"00:16:3E:A8:B5:D7\"\n  mode               = \"tagged\"\n  mtu                = 1440\n  tagged_vlans       = [netbox_vlan.test1.id]\n  untagged_vlan      = netbox_vlan.test2.id\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_interface_template/resource.tf",
    "content": "resource \"netbox_manufacturer\" \"test\" {\n  name = \"my-manufacturer\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model           = \"test-model\"\n  slug            = \"test-model\"\n  part_number     = \"test-part-number\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_interface_template\" \"test\" {\n  name           = \"eth0\"\n  description    = \"eth0 description\"\n  label          = \"eth0 label\"\n  device_type_id = netbox_device_type.test.id\n  type           = \"100base-tx\"\n  mgmt_only      = true\n}\n"
  },
  {
    "path": "examples/resources/netbox_inventory_item/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id      = netbox_tenant.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id      = netbox_device.test.id\n  name           = \"rear port\"\n  type           = \"8p8c\"\n  positions      = 1\n  mark_connected = true\n}\n\nresource \"netbox_inventory_item\" \"parent\" {\n  device_id = netbox_device.test.id\n  name      = \"Parent Item\"\n}\n\nresource \"netbox_inventory_item\" \"test\" {\n  device_id = netbox_device.test.id\n  name      = \"Child Item\"\n  parent_id = netbox_inventory_item.parent.id\n\n  component_type = \"dcim.rearport\"\n  component_id   = netbox_device_rear_port.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_inventory_item_role/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id      = netbox_tenant.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_inventory_item_role\" \"test\" {\n  name      = \"Role 1\"\n  slug      = \"role-1-slug\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_inventory_item\" \"parent\" {\n  device_id = netbox_device.test.id\n  name      = \"Inventory Item 1\"\n  role_id   = netbox_inventory_item_role.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_ip_address/device_interface_id.tf",
    "content": "// Assuming a device with the id `123` exists\nresource \"netbox_device_interface\" \"this\" {\n  name      = \"eth0\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"this\" {\n  ip_address          = \"10.0.0.60/24\"\n  status              = \"active\"\n  device_interface_id = netbox_device_interface.this.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_ip_address/object_type_device.tf",
    "content": "// Assuming a device with the id `123` exists\nresource \"netbox_device_interface\" \"this\" {\n  name      = \"eth0\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"this\" {\n  ip_address   = \"10.0.0.60/24\"\n  status       = \"active\"\n  interface_id = netbox_device_interface.this.id\n  object_type  = \"dcim.interface\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_ip_address/object_type_virtual_machine.tf",
    "content": "// Assuming a virtual machine with the id `123` exists\nresource \"netbox_interface\" \"this\" {\n  name               = \"eth0\"\n  virtual_machine_id = 123\n}\n\nresource \"netbox_ip_address\" \"this\" {\n  ip_address   = \"10.0.0.60/24\"\n  status       = \"active\"\n  interface_id = netbox_interface.this.id\n  object_type  = \"virtualization.vminterface\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_ip_address/standalone.tf",
    "content": "resource \"netbox_ip_address\" \"this\" {\n  ip_address = \"10.0.0.50/24\"\n  status     = \"reserved\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_ip_address/virtual_machine_interface_id.tf",
    "content": "// Assuming a virtual machine with the id `123` exists\nresource \"netbox_interface\" \"this\" {\n  name               = \"eth0\"\n  virtual_machine_id = 123\n}\n\nresource \"netbox_ip_address\" \"this\" {\n  ip_address                   = \"10.0.0.60/24\"\n  status                       = \"active\"\n  virtual_machine_interface_id = netbox_interface.this.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_ip_range/resource.tf",
    "content": "resource \"netbox_ip_range\" \"cust_a_prod\" {\n  start_address = \"10.0.0.1/24\"\n  end_address   = \"10.0.0.50/24\"\n  tags          = [\"customer-a\", \"prod\"]\n}\n"
  },
  {
    "path": "examples/resources/netbox_ipam_role/resource.tf",
    "content": "resource \"netbox_ipam_role\" \"test_basic\" {\n  name = \"test\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_location/resource.tf",
    "content": "resource \"netbox_site\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"test\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name        = \"test\"\n  description = \"my description\"\n  site_id     = netbox_site.test.id\n  tenant_id   = netbox_tenant.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_mac_address/device_interface_id.tf",
    "content": "// Assuming a device with the id `123` exists\nresource \"netbox_device_interface\" \"this\" {\n  name      = \"eth0\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_mac_address\" \"this\" {\n  mac_address         = \"00:1A:2B:3C:4D:5E\"\n  device_interface_id = netbox_device_interface.this.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_mac_address/object_type_device.tf",
    "content": "// Assuming a device with the id `123` exists\nresource \"netbox_device_interface\" \"this\" {\n  name      = \"eth0\"\n  device_id = 123\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_mac_address\" \"this\" {\n  mac_address  = \"00:1A:2B:3C:4D:5E\"\n  interface_id = netbox_device_interface.this.id\n  object_type  = \"dcim.interface\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_mac_address/object_type_virtual_machine.tf",
    "content": "// Assuming a virtual machine with the id `123` exists\nresource \"netbox_interface\" \"this\" {\n  name               = \"eth0\"\n  virtual_machine_id = 123\n}\n\nresource \"netbox_mac_address\" \"this\" {\n  mac_address  = \"00:1A:2B:3C:4D:5E\"\n  interface_id = netbox_interface.this.id\n  object_type  = \"virtualization.vminterface\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_mac_address/standalone.tf",
    "content": "resource \"netbox_mac_address\" \"this\" {\n  mac_address = \"00:1A:2B:3C:4D:5E\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_mac_address/virtual_machine_interface_id.tf",
    "content": "// Assuming a virtual machine with the id `123` exists\nresource \"netbox_interface\" \"this\" {\n  name               = \"eth0\"\n  virtual_machine_id = 123\n}\n\nresource \"netbox_mac_address\" \"this\" {\n  mac_address                  = \"00:1A:2B:3C:4D:5E\"\n  virtual_machine_interface_id = netbox_interface.this.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_manufacturer/resource.tf",
    "content": "resource \"netbox_manufacturer\" \"test\" {\n  name = \"testmanufacturer\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_module/resource.tf",
    "content": "# Note that some terraform code is not included in the example for brevity\n\nresource \"netbox_device\" \"test\" {\n  name           = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id        = netbox_device_role.test.id\n  site_id        = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name      = \"SFP\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"Dell\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model           = \"Networking\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id      = netbox_device.test.id\n  module_bay_id  = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status         = \"active\"\n\n  description = \"SFP card\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_module_type/resource.tf",
    "content": "resource \"netbox_manufacturer\" \"test\" {\n  name = \"Dell\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model           = \"Networking\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_permission/resource.tf",
    "content": "resource \"netbox_user\" \"test\" {\n  username = \"johndoe\"\n  password = \"Abcdefghijkl1\"\n  active   = true\n  staff    = true\n}\n\nresource \"netbox_permission\" \"test\" {\n  name         = \"test\"\n  description  = \"my description\"\n  enabled      = true\n  object_types = [\"ipam.prefix\"]\n  actions      = [\"add\", \"change\"]\n  users        = [netbox_user.test.id]\n  constraints = jsonencode([{\n    \"status\" = \"active\"\n  }])\n}\n"
  },
  {
    "path": "examples/resources/netbox_platform/resource.tf",
    "content": "// Resource for PanOS (e.g. Panorama from Palo Alto)\nresource \"netbox_platform\" \"PANOS\" {\n  name = \"PANOS\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_power_feed/resource.tf",
    "content": "resource \"netbox_site\" \"test\" {\n  name   = \"Site 1\"\n  status = \"active\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name    = \"Location 1\"\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_power_panel\" \"test\" {\n  name        = \"Power Panel 1\"\n  site_id     = netbox_site.test.id\n  location_id = netbox_location.test.id\n}\n\nresource \"netbox_power_feed\" \"test\" {\n  power_panel_id          = netbox_power_panel.test.id\n  name                    = \"Power Feed 1\"\n  status                  = \"active\"\n  type                    = \"primary\"\n  supply                  = \"ac\"\n  phase                   = \"single-phase\"\n  voltage                 = 250\n  amperage                = 100\n  max_percent_utilization = 80\n}\n"
  },
  {
    "path": "examples/resources/netbox_power_panel/resource.tf",
    "content": "resource \"netbox_site\" \"test\" {\n  name   = \"Site 1\"\n  status = \"active\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name    = \"Location 1\"\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_power_panel\" \"test\" {\n  name        = \"Power Panel 1\"\n  site_id     = netbox_site.test.id\n  location_id = netbox_location.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_prefix/resource.tf",
    "content": "resource \"netbox_prefix\" \"my_prefix\" {\n  prefix      = \"10.0.0.0/24\"\n  status      = \"active\"\n  description = \"test prefix\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_primary_ip/resource.tf",
    "content": "// Assumes Netbox already has a VM whos name matches 'dc-west-myvm-20'\ndata \"netbox_virtual_machine\" \"myvm\" {\n  name_regex = \"dc-west-myvm-20\"\n}\n\nresource \"netbox_interface\" \"myvm_eth0\" {\n  name               = \"eth0\"\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n\nresource \"netbox_ip_address\" \"myvm_ip\" {\n  ip_address   = \"10.0.0.60/24\"\n  status       = \"active\"\n  interface_id = netbox_interface.myvm_eth0.id\n}\n\nresource \"netbox_primary_ip\" \"myvm_primary_ip\" {\n  ip_address_id      = netbox_ip_address.myvm_ip.id\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_rack/resource.tf",
    "content": "resource \"netbox_site\" \"test\" {\n  name   = \"test\"\n  status = \"active\"\n}\n\nresource \"netbox_rack\" \"test\" {\n  name     = \"test\"\n  site_id  = netbox_site.test.id\n  status   = \"reserved\"\n  width    = 19\n  u_height = 48\n}\n"
  },
  {
    "path": "examples/resources/netbox_rack_reservation/resource.tf",
    "content": "resource \"netbox_site\" \"test\" {\n  name   = \"test\"\n  status = \"active\"\n}\n\nresource \"netbox_rack\" \"test\" {\n  name     = \"test\"\n  site_id  = netbox_site.test.id\n  status   = \"active\"\n  width    = 10\n  u_height = 40\n}\nresource \"netbox_rack_reservation\" \"test\" {\n  rack_id     = netbox_rack.test.id\n  units       = [1, 2, 3, 4, 5]\n  user_id     = 1\n  description = \"my description\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_rack_role/resource.tf",
    "content": "resource \"netbox_rack_role\" \"test\" {\n  name      = \"test\"\n  color_hex = \"111111\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_rack_type/resource.tf",
    "content": "resource \"netbox_manufacturer\" \"test\" {\n  name = \"my-manufacturer\"\n}\n\nresource \"netbox_rack_type\" \"test\" {\n  model             = \"mymodel\"\n  manufacturer_id   = netbox_manufacturer.test.id\n  width             = 19\n  u_height          = 48\n  starting_unit     = 1\n  form_factor       = \"2-post-frame\"\n  description       = \"My description\"\n  outer_width       = 10\n  outer_depth       = 15\n  outer_unit        = \"mm\"\n  weight            = 15\n  max_weight        = 20\n  weight_unit       = \"kg\"\n  mounting_depth_mm = 21\n  comments          = \"My comments\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_region/resource.tf",
    "content": "resource \"netbox_region\" \"test\" {\n  name        = \"test\"\n  description = \"test description\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_rir/resource.tf",
    "content": "resource \"netbox_rir\" \"test\" {\n  name        = \"test\"\n  description = \"my description\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_route_target/resource.tf",
    "content": "resource \"netbox_tenant\" \"test\" {\n  name = \"test\"\n}\nresource \"netbox_route_target\" \"test\" {\n  name        = \"test\"\n  description = \"my description\"\n  tenant_id   = netbox_tenant.test.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_service/resource.tf",
    "content": "// Assumes Netbox already has a VM whos name matches 'dc-west-myvm-20'\ndata \"netbox_virtual_machine\" \"myvm\" {\n  name_regex = \"dc-west-myvm-20\"\n}\n\nresource \"netbox_service\" \"ssh\" {\n  name               = \"ssh\"\n  ports              = [22]\n  protocol           = \"tcp\"\n  virtual_machine_id = data.netbox_virtual_machine.myvm.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_site/resource.tf",
    "content": "resource \"netbox_site\" \"example1\" {\n  name      = \"Example site 1\"\n  asn       = 1337\n  facility  = \"Data center\"\n  latitude  = \"-45.4085\"\n  longitude = \"30.1496\"\n  status    = \"staging\"\n  timezone  = \"Africa/Johannesburg\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_site_group/resource.tf",
    "content": "resource \"netbox_site_group\" \"parent\" {\n  name        = \"parent\"\n  description = \"sample description\"\n}\n\nresource \"netbox_site_group\" \"child\" {\n  name        = \"child\"\n  description = \"sample description\"\n\n  parent_id = netbox_site_group.parent.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_tag/resource.tf",
    "content": "resource \"netbox_tag\" \"dmz\" {\n  name      = \"DMZ\"\n  color_hex = \"ff00ff\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_tenant/resource.tf",
    "content": "resource \"netbox_tenant\" \"customer_a\" {\n  name = \"Customer A\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_tenant_group/resource.tf",
    "content": "resource \"netbox_tenant_group\" \"test\" {\n  name = \"test-tenant-group\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_token/resource.tf",
    "content": "resource \"netbox_user\" \"test\" {\n  username = \"johndoe\"\n  password = \"Abcdefghijkl1\"\n}\n\nresource \"netbox_token\" \"test_basic\" {\n  user_id       = netbox_user.test.id\n  key           = \"0123456789012345678901234567890123456789\"\n  allowed_ips   = [\"2.4.8.16/32\"]\n  write_enabled = false\n  expires       = \"2036-01-02T15:04:05.000Z\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_user/resource.tf",
    "content": "resource \"netbox_user\" \"test\" {\n  username = \"johndoe\"\n  password = \"Abcdefghijkl1\"\n  active   = true\n  staff    = true\n}\n"
  },
  {
    "path": "examples/resources/netbox_virtual_chassis/resource.tf",
    "content": "resource \"netbox_virtual_chassis\" \"example\" {\n  name        = \"chassis\"\n  domain      = \"domain\"\n  description = \"virtual chassis\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_virtual_disk/resource.tf",
    "content": "// Assumes vmw-cluster-01 exists in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\nresource \"netbox_virtual_machine\" \"base_vm\" {\n  cluster_id = data.netbox_cluster.vmw_cluster_01.id\n  name       = \"myvm-1\"\n}\n\nresource \"netbox_virtual_disk\" \"example\" {\n  name               = \"disk-01\"\n  description        = \"Main disk\"\n  size_mb            = 50\n  virtual_machine_id = netbox_virtual_machine.base_vm.id\n}\n"
  },
  {
    "path": "examples/resources/netbox_virtual_machine/resource.tf",
    "content": "// Assumes vmw-cluster-01 exists in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\nresource \"netbox_virtual_machine\" \"base_vm\" {\n  cluster_id = data.netbox_cluster.vmw_cluster_01.id\n  name       = \"myvm-1\"\n}\n// Assumes vmw-cluster-01 exists in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\nresource \"netbox_virtual_machine\" \"basic_vm\" {\n  cluster_id   = data.netbox_cluster.vmw_cluster_01.id\n  name         = \"myvm-2\"\n  disk_size_mb = 40000\n  memory_mb    = 4092\n  vcpus        = \"2\"\n}\n// Assumes vmw-cluster-01 exists as a cluster in Netbox\ndata \"netbox_cluster\" \"vmw_cluster_01\" {\n  name = \"vmw-cluster-01\"\n}\n\n// Assumes customer-a exists as a tenant in Netbox\ndata \"netbox_tenant\" \"customer_a\" {\n  name = \"Customer A\"\n}\n\nresource \"netbox_virtual_machine\" \"full_vm\" {\n  cluster_id   = data.netbox_cluster.vmw_cluster_01.id\n  name         = \"myvm-3\"\n  disk_size_mb = 40000\n  memory_mb    = 4092\n  vcpus        = \"2\"\n  role_id      = 31 // This corresponds to the Netbox ID for a given role\n  tenant_id    = data.netbox_tenant.customer_a.id\n  local_context_data = jsonencode({\n    \"setting_a\" = \"Some Setting\"\n    \"setting_b\" = 42\n  })\n}\n"
  },
  {
    "path": "examples/resources/netbox_vlan/resource.tf",
    "content": "resource \"netbox_vlan\" \"example1\" {\n  name = \"VLAN 1\"\n  vid  = 1777\n  tags = []\n}\n\n# Assume netbox_tenant, netbox_site, and netbox_tag resources exist\nresource \"netbox_vlan\" \"example2\" {\n  name        = \"VLAN 2\"\n  vid         = 1778\n  status      = \"reserved\"\n  description = \"Reserved example VLAN\"\n  tenant_id   = netbox_tenant.ex.id\n  site_id     = netbox_site.ex.id\n  group_id    = netbox_vlan_group.ex.id\n  tags        = [netbox_tag.ex.name]\n}\n"
  },
  {
    "path": "examples/resources/netbox_vlan_group/resource.tf",
    "content": "#Basic VLAN Group example\nresource \"netbox_vlan_group\" \"example1\" {\n  name = \"example1\"\n  slug = \"example1\"\n}\n\n#Full VLAN Group example\nresource \"netbox_vlan_group\" \"example2\" {\n  name        = \"Second Example\"\n  slug        = \"example2\"\n  scope_type  = \"dcim.site\"\n  scope_id    = netbox_site.example.id\n  description = \"Second Example VLAN Group\"\n  tags        = [netbox_tag.example.id]\n  vid_ranges  = [[1, 2], [3, 4]]\n}\n"
  },
  {
    "path": "examples/resources/netbox_vpn_tunnel/resource.tf",
    "content": "resource \"netbox_vpn_tunnel_group\" \"test\" {\n  name = \"my-tunnel-group\"\n}\n\nresource \"netbox_vpn_tunnel\" \"test\" {\n  name            = \"my-tunnel\"\n  encapsulation   = \"ipsec-transport\"\n  status          = \"active\"\n  tunnel_group_id = netbox_vpn_tunnel_group.test.id\n\n  description = \"This is a description.\"\n  tunnel_id   = 3\n  tenant_id   = 2\n}\n"
  },
  {
    "path": "examples/resources/netbox_vpn_tunnel_group/resource.tf",
    "content": "resource \"netbox_vpn_tunnel_group\" \"test\" {\n  name = \"my-tunnel-group\"\n\n  description = \"My description\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_vpn_tunnel_termination/resource.tf",
    "content": "resource \"netbox_vpn_tunnel_group\" \"test\" {\n  name        = \"my-tunnel-group\"\n  description = \"description\"\n}\n\nresource \"netbox_vpn_tunnel\" \"test\" {\n  name            = \"my-tunnel\"\n  encapsulation   = \"ipsec-transport\"\n  status          = \"active\"\n  tunnel_group_id = netbox_vpn_tunnel_group.test.id\n}\n\nresource \"netbox_vpn_tunnel_termination\" \"device\" {\n  role                = \"peer\"\n  tunnel_id           = netbox_vpn_tunnel.test.id\n  device_interface_id = 123\n}\n\nresource \"netbox_vpn_tunnel_termination\" \"vm\" {\n  role                         = \"peer\"\n  tunnel_id                    = netbox_vpn_tunnel.test.id\n  virtual_machine_interface_id = 234\n}\n"
  },
  {
    "path": "examples/resources/netbox_vrf/resource.tf",
    "content": "resource \"netbox_vrf\" \"cust_a_prod\" {\n  name = \"cust-a-prod\"\n  tags = [\"customer-a\", \"prod\"]\n}\n"
  },
  {
    "path": "examples/resources/netbox_webhook/resource.tf",
    "content": "resource \"netbox_webhook\" \"test\" {\n  name         = \"test\"\n  payload_url  = \"https://example.com/webhook\"\n  bodytemplate = \"Sample body\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_wireless_lan/resource.tf",
    "content": "resource \"netbox_wireless_lan\" \"guest\" {\n  ssid   = \"guest-wifi\"\n  status = \"active\"\n}\n"
  },
  {
    "path": "examples/resources/netbox_wireless_lan_group/resource.tf",
    "content": "resource \"netbox_wireless_lan_group\" \"parent\" {\n  name = \"campus\"\n}\n\nresource \"netbox_wireless_lan_group\" \"child\" {\n  name      = \"building-a\"\n  parent_id = netbox_wireless_lan_group.parent.id\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/e-breuninger/terraform-provider-netbox\n\ngo 1.25.8\n\nrequire (\n\tgithub.com/fbreckle/go-netbox v0.0.0-20260127172814-8429073254cc\n\tgithub.com/fbreckle/terraform-plugin-docs v0.0.0-20220812121758-a828466500d3\n\tgithub.com/go-openapi/runtime v0.29.4\n\tgithub.com/go-openapi/strfmt v0.26.2\n\tgithub.com/go-viper/mapstructure/v2 v2.5.0\n\tgithub.com/goware/urlx v0.3.2\n\tgithub.com/hashicorp/terraform-plugin-sdk/v2 v2.40.1\n\tgithub.com/sirupsen/logrus v1.9.4\n\tgithub.com/stretchr/testify v1.11.1\n\tgolang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90\n)\n\nrequire (\n\tgithub.com/Masterminds/goutils v1.1.1 // indirect\n\tgithub.com/Masterminds/semver/v3 v3.2.0 // indirect\n\tgithub.com/Masterminds/sprig/v3 v3.2.3 // indirect\n\tgithub.com/ProtonMail/go-crypto v1.4.1 // indirect\n\tgithub.com/PuerkitoBio/purell v1.2.1 // indirect\n\tgithub.com/agext/levenshtein v1.2.3 // indirect\n\tgithub.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect\n\tgithub.com/armon/go-radix v1.0.0 // indirect\n\tgithub.com/bgentry/speakeasy v0.1.0 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/cloudflare/circl v1.6.3 // indirect\n\tgithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect\n\tgithub.com/fatih/color v1.19.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-openapi/analysis v0.25.0 // indirect\n\tgithub.com/go-openapi/errors v0.22.7 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.22.5 // indirect\n\tgithub.com/go-openapi/jsonreference v0.21.5 // indirect\n\tgithub.com/go-openapi/loads v0.23.3 // indirect\n\tgithub.com/go-openapi/spec v0.22.4 // indirect\n\tgithub.com/go-openapi/swag v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/cmdutils v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/conv v0.26.0 // indirect\n\tgithub.com/go-openapi/swag/fileutils v0.26.0 // indirect\n\tgithub.com/go-openapi/swag/jsonname v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/jsonutils v0.26.0 // indirect\n\tgithub.com/go-openapi/swag/loading v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/mangling v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/netutils v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/stringutils v0.26.0 // indirect\n\tgithub.com/go-openapi/swag/typeutils v0.26.0 // indirect\n\tgithub.com/go-openapi/swag/yamlutils v0.25.5 // indirect\n\tgithub.com/go-openapi/validate v0.25.2 // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/hashicorp/go-checkpoint v0.5.0 // indirect\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2 // indirect\n\tgithub.com/hashicorp/go-cty v1.5.0 // indirect\n\tgithub.com/hashicorp/go-hclog v1.6.3 // indirect\n\tgithub.com/hashicorp/go-multierror v1.1.1 // indirect\n\tgithub.com/hashicorp/go-plugin v1.7.0 // indirect\n\tgithub.com/hashicorp/go-retryablehttp v0.7.8 // indirect\n\tgithub.com/hashicorp/go-uuid v1.0.3 // indirect\n\tgithub.com/hashicorp/go-version v1.9.0 // indirect\n\tgithub.com/hashicorp/hc-install v0.9.5 // indirect\n\tgithub.com/hashicorp/hcl/v2 v2.24.0 // indirect\n\tgithub.com/hashicorp/logutils v1.0.0 // indirect\n\tgithub.com/hashicorp/terraform-exec v0.25.1 // indirect\n\tgithub.com/hashicorp/terraform-json v0.27.2 // indirect\n\tgithub.com/hashicorp/terraform-plugin-go v0.31.0 // indirect\n\tgithub.com/hashicorp/terraform-plugin-log v0.10.0 // indirect\n\tgithub.com/hashicorp/terraform-registry-address v0.4.0 // indirect\n\tgithub.com/hashicorp/terraform-svchost v0.2.1 // indirect\n\tgithub.com/hashicorp/yamux v0.1.2 // indirect\n\tgithub.com/huandu/xstrings v1.4.0 // indirect\n\tgithub.com/imdario/mergo v0.3.15 // indirect\n\tgithub.com/mattn/go-colorable v0.1.14 // indirect\n\tgithub.com/mattn/go-isatty v0.0.21 // indirect\n\tgithub.com/mitchellh/cli v1.1.5 // indirect\n\tgithub.com/mitchellh/copystructure v1.2.0 // indirect\n\tgithub.com/mitchellh/go-testing-interface v1.14.1 // indirect\n\tgithub.com/mitchellh/go-wordwrap v1.0.1 // indirect\n\tgithub.com/mitchellh/mapstructure v1.5.0 // indirect\n\tgithub.com/mitchellh/reflectwalk v1.0.2 // indirect\n\tgithub.com/oklog/run v1.2.0 // indirect\n\tgithub.com/oklog/ulid/v2 v2.1.1 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect\n\tgithub.com/posener/complete v1.2.3 // indirect\n\tgithub.com/russross/blackfriday v1.6.0 // indirect\n\tgithub.com/shopspring/decimal v1.3.1 // indirect\n\tgithub.com/spf13/cast v1.5.0 // indirect\n\tgithub.com/vmihailenco/msgpack v4.0.4+incompatible // indirect\n\tgithub.com/vmihailenco/msgpack/v5 v5.4.1 // indirect\n\tgithub.com/vmihailenco/tagparser/v2 v2.0.0 // indirect\n\tgithub.com/zclconf/go-cty v1.18.1 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.2.1 // indirect\n\tgo.opentelemetry.io/otel v1.43.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.43.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.43.0 // indirect\n\tgo.yaml.in/yaml/v3 v3.0.4 // indirect\n\tgolang.org/x/crypto v0.50.0 // indirect\n\tgolang.org/x/mod v0.35.0 // indirect\n\tgolang.org/x/net v0.53.0 // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n\tgolang.org/x/sys v0.43.0 // indirect\n\tgolang.org/x/text v0.36.0 // indirect\n\tgolang.org/x/tools v0.43.0 // indirect\n\tgoogle.golang.org/appengine v1.6.8 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d // indirect\n\tgoogle.golang.org/grpc v1.80.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.11 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=\ndario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=\ngithub.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=\ngithub.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=\ngithub.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=\ngithub.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=\ngithub.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=\ngithub.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=\ngithub.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=\ngithub.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=\ngithub.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=\ngithub.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=\ngithub.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM=\ngithub.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=\ngithub.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=\ngithub.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28=\ngithub.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=\ngithub.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=\ngithub.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=\ngithub.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=\ngithub.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=\ngithub.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=\ngithub.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=\ngithub.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=\ngithub.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=\ngithub.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=\ngithub.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=\ngithub.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=\ngithub.com/fbreckle/go-netbox v0.0.0-20260127172814-8429073254cc h1:hD25F2J/e992lL1qXa94qM+Hv1ieqn6evPWaJM8WN9c=\ngithub.com/fbreckle/go-netbox v0.0.0-20260127172814-8429073254cc/go.mod h1:3U3/m/hna9Ntd3sbHBYwZ1IqbP2+coRzoXw3mCfu3kM=\ngithub.com/fbreckle/terraform-plugin-docs v0.0.0-20220812121758-a828466500d3 h1:DMSpM0btVedE2Tt1vfDHWQhf2obzjAe1F0/j8/CyfW4=\ngithub.com/fbreckle/terraform-plugin-docs v0.0.0-20220812121758-a828466500d3/go.mod h1:j3HmJySEjx6hOAOPDjGzmzpVNDQq9SNnnF+Vm22d2rs=\ngithub.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=\ngithub.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=\ngithub.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=\ngithub.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=\ngithub.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0=\ngithub.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=\ngithub.com/go-git/go-git/v5 v5.18.0 h1:O831KI+0PR51hM2kep6T8k+w0/LIAD490gvqMCvL5hM=\ngithub.com/go-git/go-git/v5 v5.18.0/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-openapi/analysis v0.25.0 h1:EnjAq1yO8wEO9HbPmY8vLPEIkdZuuFhCAKBPvCB7bCs=\ngithub.com/go-openapi/analysis v0.25.0/go.mod h1:5WFTRE43WLkPG9r9OtlMfqkkvUTYLVVCIxLlEpyF8kE=\ngithub.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA=\ngithub.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w=\ngithub.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=\ngithub.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=\ngithub.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=\ngithub.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=\ngithub.com/go-openapi/loads v0.23.3 h1:g5Xap1JfwKkUnZdn+S0L3SzBDpcTIYzZ5Qaag0YDkKQ=\ngithub.com/go-openapi/loads v0.23.3/go.mod h1:NOH07zLajXo8y55hom0omlHWDVVvCwBM/S+csCK8LqA=\ngithub.com/go-openapi/runtime v0.29.4 h1:k2lDxrGoSAJRdhFG2tONKMpkizY/4X1cciSdtzk4Jjo=\ngithub.com/go-openapi/runtime v0.29.4/go.mod h1:K0k/2raY6oqXJnZAgWJB2i/12QKrhUKpZcH4PfV9P18=\ngithub.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ=\ngithub.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=\ngithub.com/go-openapi/strfmt v0.26.2 h1:ysjheCh4i1rmFEo2LanhELDNucNzfWTZhUDKgWWPaFM=\ngithub.com/go-openapi/strfmt v0.26.2/go.mod h1:fXh1e449cyUn2NYuz+wb3wARBUdMl7qPEZwX00nqivY=\ngithub.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=\ngithub.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=\ngithub.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=\ngithub.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=\ngithub.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I=\ngithub.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE=\ngithub.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU=\ngithub.com/go-openapi/swag/fileutils v0.26.0/go.mod h1:0WDJ7lp67eNjPMO50wAWYlKvhOb6CQ37rzR7wrgI8Tc=\ngithub.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=\ngithub.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=\ngithub.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA=\ngithub.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E=\ngithub.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM=\ngithub.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y=\ngithub.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=\ngithub.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=\ngithub.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw=\ngithub.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY=\ngithub.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU=\ngithub.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14=\ngithub.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg=\ngithub.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE=\ngithub.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4=\ngithub.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE=\ngithub.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=\ngithub.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=\ngithub.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0=\ngithub.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE=\ngithub.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=\ngithub.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=\ngithub.com/go-openapi/validate v0.25.2 h1:12NsfLAwGegqbGWr2CnvT65X/Q2USJipmJ9b7xDJZz0=\ngithub.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocKypgE+8Q8BLfY=\ngithub.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=\ngithub.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=\ngithub.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=\ngithub.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=\ngithub.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=\ngithub.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=\ngithub.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/goware/urlx v0.3.2 h1:gdoo4kBHlkqZNaf6XlQ12LGtQOmpKJrR04Rc3RnpJEo=\ngithub.com/goware/urlx v0.3.2/go.mod h1:h8uwbJy68o+tQXCGZNa9D73WN8n0r9OBae5bUnLcgjw=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=\ngithub.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-cty v1.5.0 h1:EkQ/v+dDNUqnuVpmS5fPqyY71NXVgT5gf32+57xY8g0=\ngithub.com/hashicorp/go-cty v1.5.0/go.mod h1:lFUCG5kd8exDobgSfyj4ONE/dc822kiYMguVKdHGMLM=\ngithub.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=\ngithub.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=\ngithub.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=\ngithub.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=\ngithub.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=\ngithub.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=\ngithub.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/hc-install v0.9.5 h1:XHCjcMn2563ysuaQ9v9ec2FNc7c2PJOIEEGobAFeIx4=\ngithub.com/hashicorp/hc-install v0.9.5/go.mod h1:ihEW4LshrNkxq2bU/MpVbKyn+yt1is2hYqUTHDGhG84=\ngithub.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE=\ngithub.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=\ngithub.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/terraform-exec v0.25.1 h1:PRutYRGM8pixV3B8812NYoBK5O+yuf3qcB/70KFKGiU=\ngithub.com/hashicorp/terraform-exec v0.25.1/go.mod h1:+izOYrs9sKMQK4OYvGDnrSSJHY/pm4e4eXFqSL2Q5mA=\ngithub.com/hashicorp/terraform-json v0.27.2 h1:BwGuzM6iUPqf9JYM/Z4AF1OJ5VVJEEzoKST/tRDBJKU=\ngithub.com/hashicorp/terraform-json v0.27.2/go.mod h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE=\ngithub.com/hashicorp/terraform-plugin-go v0.31.0 h1:0Fz2r9DQ+kNNl6bx8HRxFd1TfMKUvnrOtvJPmp3Z0q8=\ngithub.com/hashicorp/terraform-plugin-go v0.31.0/go.mod h1:A88bDhd/cW7FnwqxQRz3slT+QY6yzbHKc6AOTtmdeS8=\ngithub.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=\ngithub.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=\ngithub.com/hashicorp/terraform-plugin-sdk/v2 v2.40.1 h1:2yPUd7esMOpuTaG3y1iEla1iw+tla+3ZEkkBnmOAre4=\ngithub.com/hashicorp/terraform-plugin-sdk/v2 v2.40.1/go.mod h1:sq8qsxh+PwdvTQFcd17kfCoBgQo46ADNMvCpKE7t/gY=\ngithub.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=\ngithub.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=\ngithub.com/hashicorp/terraform-svchost v0.2.1 h1:ubvrTFw3Q7CsoEaX7V06PtCTKG3wu7GyyobAoN4eF3Q=\ngithub.com/hashicorp/terraform-svchost v0.2.1/go.mod h1:zDMheBLvNzu7Q6o9TBvPqiZToJcSuCLXjAXxBslSky4=\ngithub.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=\ngithub.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=\ngithub.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=\ngithub.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=\ngithub.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=\ngithub.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=\ngithub.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=\ngithub.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=\ngithub.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=\ngithub.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=\ngithub.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=\ngithub.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=\ngithub.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=\ngithub.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng=\ngithub.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=\ngithub.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=\ngithub.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=\ngithub.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=\ngithub.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=\ngithub.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=\ngithub.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=\ngithub.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=\ngithub.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=\ngithub.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=\ngithub.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=\ngithub.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=\ngithub.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E=\ngithub.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk=\ngithub.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=\ngithub.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=\ngithub.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=\ngithub.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=\ngithub.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=\ngithub.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=\ngithub.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=\ngithub.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=\ngithub.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=\ngithub.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=\ngithub.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=\ngithub.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=\ngithub.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=\ngithub.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=\ngithub.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=\ngithub.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=\ngithub.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=\ngithub.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=\ngithub.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=\ngithub.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=\ngithub.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=\ngithub.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngithub.com/zclconf/go-cty v1.18.1 h1:yEGE8M4iIZlyKQURZNb2SnEyZlZHUcBCnx6KF81KuwM=\ngithub.com/zclconf/go-cty v1.18.1/go.mod h1:qpnV6EDNgC1sns/AleL1fvatHw72j+S+nS+MJ+T2CSg=\ngithub.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=\ngithub.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=\ngo.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=\ngo.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=\ngo.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=\ngo.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=\ngo.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=\ngo.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=\ngo.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=\ngo.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=\ngo.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=\ngo.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=\ngolang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=\ngolang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=\ngolang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=\ngolang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=\ngolang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=\ngolang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=\ngolang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=\ngolang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=\ngolang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=\ngolang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=\ngolang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=\ngolang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=\ngolang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=\ngonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=\ngoogle.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d h1:wT2n40TBqFY6wiwazVK9/iTWbsQrgk5ZfCSVFLO9LQA=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=\ngoogle.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=\ngoogle.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=\ngopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\n\t\"github.com/e-breuninger/terraform-provider-netbox/netbox\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/plugin\"\n)\n\n// Run \"go generate\" to format example terraform files and generate the docs for the registry/website\n\n// Run the docs generation tool, check its repository for more information on how it works and how docs\n// can be customized.\n//go:generate go run github.com/fbreckle/terraform-plugin-docs/cmd/tfplugindocs\n\nfunc main() {\n\tvar debug bool\n\n\tflag.BoolVar(&debug, \"debug\", false, \"set to true to run the provider with support for debuggers like delve\")\n\tflag.Parse()\n\n\tplugin.Serve(&plugin.ServeOpts{\n\t\tDebug:        debug,\n\t\tProviderAddr: \"registry.terraform.io/e-breuninger/netbox\",\n\t\tProviderFunc: func() *schema.Provider {\n\t\t\treturn netbox.Provider()\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/client.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\tnetboxclient \"github.com/fbreckle/go-netbox/netbox/client\"\n\thttptransport \"github.com/go-openapi/runtime/client\"\n\t\"github.com/goware/urlx\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// Config struct for the netbox provider\ntype Config struct {\n\tAPIToken                    string\n\tServerURL                   string\n\tAllowInsecureHTTPS          bool\n\tHeaders                     map[string]interface{}\n\tRequestTimeout              int\n\tStripTrailingSlashesFromURL bool\n\tCACertFile                  string\n}\n\n// customHeaderTransport is a transport that adds the specified headers on\n// every request.\ntype customHeaderTransport struct {\n\toriginal http.RoundTripper\n\theaders  map[string]interface{}\n}\n\n// Client does the heavy lifting of establishing a base Open API client to Netbox.\nfunc (cfg *Config) Client() (*netboxclient.NetBoxAPI, error) {\n\tlog.WithFields(log.Fields{\n\t\t\"server_url\": cfg.ServerURL,\n\t}).Debug(\"Initializing Netbox client\")\n\n\tif cfg.APIToken == \"\" {\n\t\treturn nil, fmt.Errorf(\"missing netbox API key\")\n\t}\n\n\t// parse serverUrl\n\tparsedURL, urlParseError := urlx.Parse(cfg.ServerURL)\n\tif urlParseError != nil {\n\t\treturn nil, fmt.Errorf(\"error while trying to parse URL: %s\", urlParseError)\n\t}\n\n\tdesiredRuntimeClientSchemes := []string{parsedURL.Scheme}\n\tlog.WithFields(log.Fields{\n\t\t\"host\":    parsedURL.Host,\n\t\t\"schemes\": desiredRuntimeClientSchemes,\n\t}).Debug(\"Initializing Netbox Open API runtime client\")\n\n\t// build http client\n\tclientOpts := httptransport.TLSClientOptions{\n\t\tCA:                 cfg.CACertFile,\n\t\tInsecureSkipVerify: cfg.AllowInsecureHTTPS,\n\t}\n\n\ttrans, err := httptransport.TLSTransport(clientOpts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttrans.(*http.Transport).Proxy = http.ProxyFromEnvironment\n\n\tif len(cfg.Headers) > 0 {\n\t\tlog.WithFields(log.Fields{\n\t\t\t\"custom_headers\": cfg.Headers,\n\t\t}).Debug(\"Setting custom headers on every request to Netbox\")\n\n\t\ttrans = customHeaderTransport{\n\t\t\toriginal: trans,\n\t\t\theaders:  cfg.Headers,\n\t\t}\n\t}\n\n\thttpClient := &http.Client{\n\t\tTransport: trans,\n\t\tTimeout:   time.Second * time.Duration(cfg.RequestTimeout),\n\t}\n\n\ttransport := httptransport.NewWithClient(parsedURL.Host, parsedURL.Path+netboxclient.DefaultBasePath, desiredRuntimeClientSchemes, httpClient)\n\tauthScheme := \"Token\"\n\tif strings.HasPrefix(cfg.APIToken, \"nbt_\") {\n\t\tauthScheme = \"Bearer\"\n\t}\n\ttransport.DefaultAuthentication = httptransport.APIKeyAuth(\"Authorization\", \"header\", fmt.Sprintf(\"%s %v\", authScheme, cfg.APIToken))\n\ttransport.SetLogger(log.StandardLogger())\n\tnetboxClient := netboxclient.New(transport, nil)\n\n\treturn netboxClient, nil\n}\n\n// RoundTrip adds the headers specified in the transport on every request.\nfunc (t customHeaderTransport) RoundTrip(r *http.Request) (*http.Response, error) {\n\tfor key, value := range t.headers {\n\t\tr.Header.Add(key, fmt.Sprintf(\"%v\", value))\n\t}\n\n\tresp, err := t.original.RoundTrip(r)\n\treturn resp, err\n}\n"
  },
  {
    "path": "netbox/client_test.go",
    "content": "package netbox\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/status\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestValidClientWithAllData(t *testing.T) {\n\tconfig := Config{\n\t\tAPIToken:  \"07b12b765127747e4afd56cb531b7bf9c61f3c30\",\n\t\tServerURL: \"https://localhost:8080\",\n\t}\n\n\tclient, err := config.Client()\n\tassert.NotNil(t, client)\n\tassert.NoError(t, err)\n}\n\nfunc TestURLMissingSchemaShouldWork(t *testing.T) {\n\tconfig := Config{\n\t\tAPIToken:  \"07b12b765127747e4afd56cb531b7bf9c61f3c30\",\n\t\tServerURL: \"localhost:8080\",\n\t}\n\n\tclient, err := config.Client()\n\tassert.NotNil(t, client)\n\tassert.NoError(t, err)\n}\n\nfunc TestURLMaleformedUrlShouldFail(t *testing.T) {\n\tconfig := Config{\n\t\tAPIToken:  \"07b12b765127747e4afd56cb531b7bf9c61f3c30\",\n\t\tServerURL: \"xyz:/localhost:8080\",\n\t}\n\n\t_, err := config.Client()\n\tassert.Error(t, err)\n}\n\nfunc TestURLMissingPortShouldWork(t *testing.T) {\n\tconfig := Config{\n\t\tAPIToken:  \"07b12b765127747e4afd56cb531b7bf9c61f3c30\",\n\t\tServerURL: \"http://localhost\",\n\t}\n\n\tclient, err := config.Client()\n\tassert.NotNil(t, client)\n\tassert.NoError(t, err)\n}\n\nfunc TestURLMissingAccessKey(t *testing.T) {\n\tconfig := Config{\n\t\tAPIToken:  \"\",\n\t\tServerURL: \"http://localhost\",\n\t}\n\n\t_, err := config.Client()\n\tassert.Error(t, err)\n}\n\nfunc TestAdditionalHeadersSet(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvals, ok := r.Header[\"Hello\"]\n\n\t\tassert.True(t, ok)\n\t\tassert.Len(t, vals, 1)\n\t\tassert.Equal(t, vals[0], \"World!\")\n\t}))\n\tdefer ts.Close()\n\n\tconfig := Config{\n\t\tAPIToken:  \"07b12b765127747e4afd56cb531b7bf9c61f3c30\",\n\t\tServerURL: ts.URL,\n\t\tHeaders: map[string]interface{}{\n\t\t\t\"Hello\": \"World!\",\n\t\t},\n\t}\n\n\tclient, err := config.Client()\n\tassert.NoError(t, err)\n\n\treq := status.NewStatusListParams()\n\tclient.Status.StatusList(req, nil)\n}\n\nfunc TestV1TokenUsesTokenScheme(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tauth := r.Header.Get(\"Authorization\")\n\t\tassert.Equal(t, \"Token 07b12b765127747e4afd56cb531b7bf9c61f3c30\", auth)\n\t}))\n\tdefer ts.Close()\n\n\tconfig := Config{\n\t\tAPIToken:  \"07b12b765127747e4afd56cb531b7bf9c61f3c30\",\n\t\tServerURL: ts.URL,\n\t}\n\n\tclient, err := config.Client()\n\tassert.NoError(t, err)\n\n\treq := status.NewStatusListParams()\n\tclient.Status.StatusList(req, nil)\n}\n\nfunc TestV2TokenUsesBearerScheme(t *testing.T) {\n\tv2Token := \"nbt_abc1234567890abcdef.checksum1234\"\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tauth := r.Header.Get(\"Authorization\")\n\t\tassert.Equal(t, \"Bearer \"+v2Token, auth)\n\t}))\n\tdefer ts.Close()\n\n\tconfig := Config{\n\t\tAPIToken:  v2Token,\n\t\tServerURL: ts.URL,\n\t}\n\n\tclient, err := config.Client()\n\tassert.NoError(t, err)\n\n\treq := status.NewStatusListParams()\n\tclient.Status.StatusList(req, nil)\n}\n\n/* TODO\nfunc TestInvalidHttpsCertificate(t *testing.T) {}\n*/\n"
  },
  {
    "path": "netbox/custom_fields.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/go-openapi/runtime\"\n\t\"github.com/go-openapi/strfmt\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nconst customFieldsKey = \"custom_fields\"\n\nvar customFieldsSchema = &schema.Schema{\n\tType:     schema.TypeMap,\n\tOptional: true,\n\tDefault:  nil,\n\tElem: &schema.Schema{\n\t\tType:    schema.TypeString,\n\t\tDefault: nil,\n\t},\n}\n\nfunc getCustomFields(cf interface{}) map[string]interface{} {\n\tcfm, ok := cf.(map[string]interface{})\n\tif !ok || len(cfm) == 0 {\n\t\treturn nil\n\t}\n\n\tresult := make(map[string]interface{})\n\tfor key, value := range cfm {\n\t\tif value != nil {\n\t\t\tresult[key] = value\n\t\t}\n\t}\n\n\tif len(result) == 0 {\n\t\treturn nil\n\t}\n\treturn result\n}\n\n// flattenCustomFields converts custom fields to a map where all values are strings.\n// Complex nested objects (like IP address references) are converted to JSON strings.\nfunc flattenCustomFields(cf interface{}) map[string]interface{} {\n\tcfm, ok := cf.(map[string]interface{})\n\tif !ok || len(cfm) == 0 {\n\t\treturn nil\n\t}\n\n\tresult := make(map[string]interface{})\n\tfor key, value := range cfm {\n\t\tif value == nil {\n\t\t\tresult[key] = \"\"\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check if the value is a simple type (string, number, bool)\n\t\tswitch v := value.(type) {\n\t\tcase string:\n\t\t\tresult[key] = v\n\t\tcase float64, int, int64, bool:\n\t\t\tresult[key] = fmt.Sprintf(\"%v\", v)\n\t\tdefault:\n\t\t\t// For complex types (maps, arrays, objects), convert to JSON string\n\t\t\tif jsonBytes, err := json.Marshal(value); err == nil {\n\t\t\t\tresult[key] = string(jsonBytes)\n\t\t\t} else {\n\t\t\t\t// Fallback to string representation\n\t\t\t\tresult[key] = fmt.Sprintf(\"%v\", value)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\ntype CustomFieldParams struct {\n\tparams runtime.ClientRequestWriter\n\tcfm    map[string]interface{}\n}\n\nfunc (o *CustomFieldParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {\n\tif err := o.params.WriteToRequest(r, reg); err != nil {\n\t\treturn err\n\t}\n\n\tfor k, v := range o.cfm {\n\t\tif vs, ok := v.(string); ok {\n\t\t\tif err := r.SetQueryParam(fmt.Sprintf(\"cf_%s\", url.QueryEscape(k)), vs); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc WithCustomFieldParamsOption(cfm map[string]interface{}) func(*runtime.ClientOperation) {\n\tif cfm == nil {\n\t\tcfm = make(map[string]interface{})\n\t}\n\n\treturn func(co *runtime.ClientOperation) {\n\t\tco.Params = &CustomFieldParams{\n\t\t\tparams: co.Params,\n\t\t\tcfm:    cfm,\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "netbox/custom_fields_test.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n)\n\nfunc TestFlattenCustomFields(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    interface{}\n\t\texpected map[string]interface{}\n\t}{\n\t\t{\n\t\t\tname:     \"nil input\",\n\t\t\tinput:    nil,\n\t\t\texpected: nil,\n\t\t},\n\t\t{\n\t\t\tname:     \"empty map\",\n\t\t\tinput:    map[string]interface{}{},\n\t\t\texpected: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"simple string value\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"field1\": \"value1\",\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"field1\": \"value1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"numeric values\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"int_field\":   42,\n\t\t\t\t\"int64_field\": int64(100),\n\t\t\t\t\"float_field\": 3.14,\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"int_field\":   \"42\",\n\t\t\t\t\"int64_field\": \"100\",\n\t\t\t\t\"float_field\": \"3.14\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"boolean value\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"bool_field\": true,\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"bool_field\": \"true\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"null value\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"null_field\": nil,\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"null_field\": \"\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"complex nested object (IP address reference)\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"gateway\": map[string]interface{}{\n\t\t\t\t\t\"id\":      9,\n\t\t\t\t\t\"address\": \"10.21.10.254/24\",\n\t\t\t\t\t\"display\": \"10.21.10.254/24\",\n\t\t\t\t\t\"family\": map[string]interface{}{\n\t\t\t\t\t\t\"value\": 4,\n\t\t\t\t\t\t\"label\": \"IPv4\",\n\t\t\t\t\t},\n\t\t\t\t\t\"url\": \"https://netbox.example.com/api/ipam/ip-addresses/9/\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"gateway\": `{\"address\":\"10.21.10.254/24\",\"display\":\"10.21.10.254/24\",\"family\":{\"label\":\"IPv4\",\"value\":4},\"id\":9,\"url\":\"https://netbox.example.com/api/ipam/ip-addresses/9/\"}`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"array value\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"tags\": []string{\"tag1\", \"tag2\", \"tag3\"},\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"tags\": `[\"tag1\",\"tag2\",\"tag3\"]`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"mixed types\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"text_field\":   \"simple text\",\n\t\t\t\t\"number_field\": 123,\n\t\t\t\t\"bool_field\":   false,\n\t\t\t\t\"null_field\":   nil,\n\t\t\t\t\"object_field\": map[string]interface{}{\n\t\t\t\t\t\"nested\": \"value\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"text_field\":   \"simple text\",\n\t\t\t\t\"number_field\": \"123\",\n\t\t\t\t\"bool_field\":   \"false\",\n\t\t\t\t\"null_field\":   \"\",\n\t\t\t\t\"object_field\": `{\"nested\":\"value\"}`,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tresult := flattenCustomFields(tt.input)\n\n\t\t\tif tt.expected == nil {\n\t\t\t\tif result != nil {\n\t\t\t\t\tt.Errorf(\"expected nil, got %v\", result)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif result == nil {\n\t\t\t\tt.Errorf(\"expected non-nil result, got nil\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif len(result) != len(tt.expected) {\n\t\t\t\tt.Errorf(\"expected %d fields, got %d\", len(tt.expected), len(result))\n\t\t\t}\n\n\t\t\tfor key, expectedValue := range tt.expected {\n\t\t\t\tactualValue, ok := result[key]\n\t\t\t\tif !ok {\n\t\t\t\t\tt.Errorf(\"expected field %q not found in result\", key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// For JSON strings, compare the parsed objects to avoid formatting differences\n\t\t\t\texpectedStr, expectedIsStr := expectedValue.(string)\n\t\t\t\tactualStr, actualIsStr := actualValue.(string)\n\n\t\t\t\tif expectedIsStr && actualIsStr {\n\t\t\t\t\t// Try to parse as JSON\n\t\t\t\t\tvar expectedJSON, actualJSON interface{}\n\t\t\t\t\texpectedIsJSON := json.Unmarshal([]byte(expectedStr), &expectedJSON) == nil\n\t\t\t\t\tactualIsJSON := json.Unmarshal([]byte(actualStr), &actualJSON) == nil\n\n\t\t\t\t\tif expectedIsJSON && actualIsJSON {\n\t\t\t\t\t\t// Compare as JSON objects\n\t\t\t\t\t\texpectedJSONStr, _ := json.Marshal(expectedJSON)\n\t\t\t\t\t\tactualJSONStr, _ := json.Marshal(actualJSON)\n\t\t\t\t\t\tif string(expectedJSONStr) != string(actualJSONStr) {\n\t\t\t\t\t\t\tt.Errorf(\"field %q: expected JSON %q, got %q\", key, expectedStr, actualStr)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Compare as strings\n\t\t\t\tif actualValue != expectedValue {\n\t\t\t\t\tt.Errorf(\"field %q: expected %q, got %q\", key, expectedValue, actualValue)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestFlattenCustomFields_ComplexRealWorldExample(t *testing.T) {\n\t// Simulate a real NetBox custom field response with an IP address object reference\n\tinput := map[string]interface{}{\n\t\t\"gateway\": map[string]interface{}{\n\t\t\t\"id\":          9,\n\t\t\t\"url\":         \"https://netbox.zonda.systems/api/ipam/ip-addresses/9/\",\n\t\t\t\"display\":     \"10.21.10.254/24\",\n\t\t\t\"address\":     \"10.21.10.254/24\",\n\t\t\t\"description\": \"\",\n\t\t\t\"family\": map[string]interface{}{\n\t\t\t\t\"value\": float64(4),\n\t\t\t\t\"label\": \"IPv4\",\n\t\t\t},\n\t\t},\n\t\t\"vlan_purpose\": \"management\",\n\t\t\"monitoring\":   true,\n\t\t\"priority\":     10,\n\t}\n\n\tresult := flattenCustomFields(input)\n\n\tif result == nil {\n\t\tt.Fatal(\"expected non-nil result\")\n\t}\n\n\t// Check that gateway is a JSON string\n\tgateway, ok := result[\"gateway\"].(string)\n\tif !ok {\n\t\tt.Errorf(\"expected gateway to be a string, got %T\", result[\"gateway\"])\n\t}\n\n\t// Verify we can parse the gateway JSON\n\tvar gatewayObj map[string]interface{}\n\tif err := json.Unmarshal([]byte(gateway), &gatewayObj); err != nil {\n\t\tt.Errorf(\"failed to parse gateway JSON: %v\", err)\n\t}\n\n\t// Verify the gateway object has expected fields\n\tif gatewayObj[\"address\"] != \"10.21.10.254/24\" {\n\t\tt.Errorf(\"expected address 10.21.10.254/24, got %v\", gatewayObj[\"address\"])\n\t}\n\n\t// Check simple fields\n\tif result[\"vlan_purpose\"] != \"management\" {\n\t\tt.Errorf(\"expected vlan_purpose=management, got %v\", result[\"vlan_purpose\"])\n\t}\n\n\tif result[\"monitoring\"] != \"true\" {\n\t\tt.Errorf(\"expected monitoring=true, got %v\", result[\"monitoring\"])\n\t}\n\n\tif result[\"priority\"] != \"10\" {\n\t\tt.Errorf(\"expected priority=10, got %v\", result[\"priority\"])\n\t}\n}\n\nfunc TestGetCustomFields(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    interface{}\n\t\texpected map[string]interface{}\n\t}{\n\t\t{\n\t\t\tname:     \"nil input\",\n\t\t\tinput:    nil,\n\t\t\texpected: nil,\n\t\t},\n\t\t{\n\t\t\tname:     \"empty map\",\n\t\t\tinput:    map[string]interface{}{},\n\t\t\texpected: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"valid map\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"field1\": \"value1\",\n\t\t\t\t\"field2\": 123,\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"field1\": \"value1\",\n\t\t\t\t\"field2\": 123,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"invalid type\",\n\t\t\tinput:    \"not a map\",\n\t\t\texpected: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"map with nil values excluded\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"set_field\":   \"value1\",\n\t\t\t\t\"unset_field\": nil,\n\t\t\t},\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"set_field\": \"value1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"map with only nil values returns nil\",\n\t\t\tinput: map[string]interface{}{\n\t\t\t\t\"unset1\": nil,\n\t\t\t\t\"unset2\": nil,\n\t\t\t},\n\t\t\texpected: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tresult := getCustomFields(tt.input)\n\n\t\t\tif tt.expected == nil {\n\t\t\t\tif result != nil {\n\t\t\t\t\tt.Errorf(\"expected nil, got %v\", result)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif result == nil {\n\t\t\t\tt.Errorf(\"expected non-nil result, got nil\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif len(result) != len(tt.expected) {\n\t\t\t\tt.Errorf(\"expected %d fields, got %d\", len(tt.expected), len(result))\n\t\t\t}\n\n\t\t\tfor key, expectedValue := range tt.expected {\n\t\t\t\tactualValue, ok := result[key]\n\t\t\t\tif !ok {\n\t\t\t\t\tt.Errorf(\"expected field %q not found in result\", key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif actualValue != expectedValue {\n\t\t\t\t\tt.Errorf(\"field %q: expected %v, got %v\", key, expectedValue, actualValue)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_asn.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxAsn() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxAsnRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"asn\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"asn\", \"tag\"},\n\t\t\t},\n\t\t\t\"tag\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"asn\", \"tag\"},\n\t\t\t\tDescription:  \"Tag to include in the data source filter (must match the tag's slug).\",\n\t\t\t},\n\t\t\t\"tag__n\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDescription: `Tag to exclude from the data source filter (must match the tag's slug).\nRefer to [Netbox's documentation](https://demo.netbox.dev/static/docs/rest-api/filtering/#lookup-expressions)\nfor more information on available lookup expressions.`,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"tags\": tagsSchemaRead,\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxAsnRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamAsnsListParams()\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tif asn, ok := d.Get(\"asn\").(string); ok && asn != \"\" {\n\t\tparams.Asn = &asn\n\t}\n\n\tif tag, ok := d.Get(\"tag\").(string); ok && tag != \"\" {\n\t\tparams.Tag = []string{tag} //TODO: switch schema to list?\n\t}\n\tif tagn, ok := d.Get(\"tag__n\").(string); ok && tagn != \"\" {\n\t\tparams.Tagn = &tagn\n\t}\n\n\tres, err := api.Ipam.IpamAsnsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one asn returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no asn found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.Set(\"id\", result.ID)\n\td.Set(\"asn\", strconv.FormatInt(*result.Asn, 10))\n\td.Set(\"description\", result.Description)\n\td.Set(\"tags\", getTagListFromNestedTagList(result.Tags))\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_asn_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxAsnSetUp(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_rir\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_asn\" \"test\" {\n  asn    = \"456\"\n  rir_id = netbox_rir.test.id\n  tags   = [netbox_tag.test.slug]\n}`, testName)\n}\n\nconst testAccNetboxAsnNoResult = `\ndata \"netbox_asn\" \"test\" {\n  asn = \"1337\"\n}`\n\nfunc testAccNetboxAsnByAsn() string {\n\treturn `\ndata \"netbox_asn\" \"test\" {\n  asn = \"456\"\n}`\n}\n\nfunc testAccNetboxAsnByTag(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_asn\" \"test\" {\n  tag = \"%[1]s\"\n}`, testName)\n}\n\nfunc TestAccNetboxAsnDataSource_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"asn_ds_basic\")\n\tsetUp := testAccNetboxAsnSetUp(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"asn\", \"456\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + testAccNetboxAsnNoResult,\n\t\t\t\tExpectError: regexp.MustCompile(\"no asn found matching filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxAsnByAsn(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_asn.test\", \"id\", \"netbox_asn.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxAsnByTag(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_asn.test\", \"id\", \"netbox_asn.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_asn.test\", \"asn\", \"456\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_asns.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxAsns() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxAsnsRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"asns\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"asn\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"rir_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tags\": tagsSchemaRead,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxAsnsRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamAsnsListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"asn\":\n\t\t\t\tparams.Asn = &vString\n\t\t\tcase \"asn__gte\":\n\t\t\t\tparams.AsnGte = &vString\n\t\t\tcase \"asn__lte\":\n\t\t\t\tparams.AsnLte = &vString\n\t\t\tcase \"asn__n\":\n\t\t\t\tparams.Asnn = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allAsns []*models.ASN\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Ipam.IpamAsnsList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch ASNs at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallAsns = append(allAsns, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allAsns)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allAsns))\n\tfilteredAsns := allAsns[:trimmedCount]\n\n\tif len(filteredAsns) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredAsns {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = v.ID\n\t\tmapping[\"asn\"] = v.Asn\n\t\tmapping[\"rir_id\"] = v.Rir.ID\n\t\tmapping[\"tags\"] = getTagListFromNestedTagList(v.Tags)\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"asns\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_asns_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxAsnsSetUp(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_rir\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_asn\" \"test_1\" {\n  asn    = \"123\"\n  rir_id = netbox_rir.test.id\n  tags   = [netbox_tag.test.slug]\n}\n\nresource \"netbox_asn\" \"test_2\" {\n\tasn    = \"1234\"\n\trir_id = netbox_rir.test.id\n\ttags   = [netbox_tag.test.slug]\n  }`, testName)\n}\n\nfunc testAccNetboxAsnsByAsn() string {\n\treturn `\ndata \"netbox_asns\" \"test\" {\n  filter {\n\tname = \"asn\"\n\tvalue = \"123\"\n  }\n}`\n}\n\nfunc testAccNetboxAsnsByAsnN() string {\n\treturn `\ndata \"netbox_asns\" \"test\" {\n  filter {\n\tname = \"asn__n\"\n\tvalue = \"123\"\n  }\n}`\n}\n\nfunc testAccNetboxAsnsByRange(testName string) string {\n\treturn `\ndata \"netbox_asns\" \"test\" {\n  filter {\n\tname = \"asn__gte\"\n\tvalue = \"100\"\n  }\n\n  filter {\n\tname = \"asn__lte\"\n\tvalue = \"2000\"\n  }\n}`\n}\n\nfunc TestAccNetboxAsnsDataSource_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"asns_ds_basic\")\n\tsetUp := testAccNetboxAsnsSetUp(testName)\n\t// This test cannot be run in parallel with other tests, because other tests create also ASNs\n\t// These ASNs then interfere with the __n filter test\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test_1\", \"asn\", \"123\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxAsnsByAsn(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_asns.test\", \"asns.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_asns.test\", \"asns.0.id\", \"netbox_asn.test_1\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxAsnsByAsnN(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_asns.test\", \"asns.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_asns.test\", \"asns.0.id\", \"netbox_asn.test_2\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxAsnsByRange(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_asns.test\", \"asns.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_asns.test\", \"asns.0.id\", \"netbox_asn.test_1\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_asns.test\", \"asns.1.id\", \"netbox_asn.test_2\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_available_prefix.go",
    "content": "package netbox\n\nimport (\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxAvailablePrefix() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxAvailablePrefixRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"prefix_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"prefixes_available\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"family\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"prefix\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vrf_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxAvailablePrefixRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamPrefixesAvailablePrefixesListParams()\n\n\tif prefixID, ok := d.Get(\"prefix_id\").(int); ok && prefixID != 0 {\n\t\tparams.ID = int64(prefixID)\n\t}\n\n\tres, err := api.Ipam.IpamPrefixesAvailablePrefixesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresult := res.GetPayload()\n\n\tvar s []map[string]interface{}\n\tfor _, v := range result {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"prefix\"] = v.Prefix\n\t\tmapping[\"family\"] = v.Family\n\t\tif v.Vrf != nil {\n\t\t\tmapping[\"vrf_id\"] = v.Vrf.ID\n\t\t}\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"prefixes_available\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_available_prefix_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxAvailablePrefixesDataSource_basic(t *testing.T) {\n\ttestPrefix := \"10.10.10.0/24\"\n\ttestSlug := \"available_prefixes_ds_basic\"\n\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\nresource \"netbox_prefix\" \"test_with_vrf\" {\n  prefix = \"%[2]s\"\n  status = \"active\"\n  vrf_id = netbox_vrf.test_vrf.id\n\n}\n\nresource \"netbox_vrf\" \"test_vrf\" {\n  name = \"%[1]s_test_vrf\"\n}\n\nresource \"netbox_available_prefix\" \"test_create_available_prefix\" {\n  parent_prefix_id = netbox_prefix.test_with_vrf.id\n  prefix_length    = 27\n  vrf_id           = netbox_vrf.test_vrf.id\n  status           = \"active\"\n}\n\n\ndata \"netbox_available_prefix\" \"test_available_prefix\" {\n  prefix_id = netbox_available_prefix.test_create_available_prefix.parent_prefix_id\n}\n\n`, testName, testPrefix),\n\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.#\", \"3\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.0.prefix\", \"10.10.10.32/27\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.1.prefix\", \"10.10.10.64/26\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.2.prefix\", \"10.10.10.128/25\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.0.vrf_id\", \"netbox_vrf.test_vrf\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_available_prefix.test_available_prefix\", \"prefix_id\", \"netbox_prefix.test_with_vrf\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailablePrefixesDataSource_without_vrf(t *testing.T) {\n\ttestPrefix := \"10.10.10.0/24\"\n\ttestSlug := \"available_prefixes_ds_without_vrf\"\n\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\nresource \"netbox_prefix\" \"test_with_vrf\" {\n  prefix = \"%[2]s\"\n  status = \"active\"\n}\n\nresource \"netbox_available_prefix\" \"test_create_available_prefix\" {\n  parent_prefix_id = netbox_prefix.test_with_vrf.id\n  prefix_length    = 27\n  status           = \"active\"\n}\n\n\ndata \"netbox_available_prefix\" \"test_available_prefix\" {\n  prefix_id = netbox_available_prefix.test_create_available_prefix.parent_prefix_id\n}\n\n`, testName, testPrefix),\n\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.#\", \"3\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.0.prefix\", \"10.10.10.32/27\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.1.prefix\", \"10.10.10.64/26\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.2.prefix\", \"10.10.10.128/25\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.2.vrf_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_available_prefix.test_available_prefix\", \"prefix_id\", \"netbox_prefix.test_with_vrf\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailablePrefixesDataSource_none_available(t *testing.T) {\n\ttestPrefix := \"10.10.10.0/24\"\n\ttestSlug := \"available_prefixes_ds_none_available\"\n\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\nresource \"netbox_prefix\" \"test_with_vrf\" {\n  prefix = \"%[2]s\"\n  status = \"active\"\n  vrf_id = netbox_vrf.test_vrf.id\n\n}\n\nresource \"netbox_vrf\" \"test_vrf\" {\n  name = \"%[1]s_test_vrf\"\n}\n\nresource \"netbox_available_prefix\" \"test_create_available_prefix\" {\n  count = 2\n  parent_prefix_id = netbox_prefix.test_with_vrf.id\n  prefix_length    = 25\n  vrf_id           = netbox_vrf.test_vrf.id\n  status           = \"active\"\n}\n\n\ndata \"netbox_available_prefix\" \"test_available_prefix\" {\n  prefix_id = netbox_available_prefix.test_create_available_prefix[1].parent_prefix_id\n}\n\n`, testName, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_available_prefix.test_available_prefix\", \"prefixes_available.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_available_prefix.test_available_prefix\", \"prefix_id\", \"netbox_prefix.test_with_vrf\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_cluster.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxCluster() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxClusterRead,\n\t\tDescription: `:meta:subcategory:Virtualization:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"cluster_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"id\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"site_id\", \"id\"},\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tComputed:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"site_id\", \"id\"},\n\t\t\t},\n\t\t\t\"site_group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"region_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"site_id\", \"id\"},\n\t\t\t},\n\t\t\t\"cluster_type_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"cluster_group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"scope_type\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"scope_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"custom_fields\": {\n\t\t\t\tType:     schema.TypeMap,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchemaRead,\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxClusterRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := virtualization.NewVirtualizationClustersListParams()\n\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.Name = &name\n\t}\n\n\tif siteID, ok := d.Get(\"site_id\").(int); ok && siteID != 0 {\n\t\tparams.SiteID = strToPtr(strconv.FormatInt(int64(siteID), 10))\n\t}\n\n\tif id, ok := d.Get(\"id\").(string); ok && id != \"0\" {\n\t\tparams.SetID(&id)\n\t}\n\n\tif clustergroupID, ok := d.Get(\"cluster_group_id\").(int); ok && clustergroupID != 0 {\n\t\tclustGroupStr := fmt.Sprintf(\"%d\", clustergroupID)\n\t\tparams.GroupID = &clustGroupStr\n\t}\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Virtualization.VirtualizationClustersList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one result, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no result\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.Set(\"cluster_id\", result.ID)\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"cluster_type_id\", result.Type.ID)\n\n\tif result.Group != nil {\n\t\td.Set(\"cluster_group_id\", result.Group.ID)\n\t} else {\n\t\td.Set(\"cluster_group_id\", nil)\n\t}\n\td.Set(\"comments\", result.Comments)\n\td.Set(\"description\", result.Description)\n\n\tif result.ScopeType != nil && result.ScopeID != nil {\n\t\td.Set(\"scope_type\", result.ScopeType)\n\t\td.Set(\"scope_id\", result.ScopeID)\n\t\tscopeID := result.ScopeID\n\t\tswitch scopeType := result.ScopeType; *scopeType {\n\t\tcase \"dcim.site\":\n\t\t\td.Set(\"site_id\", scopeID)\n\t\tcase \"dcim.sitegroup\":\n\t\t\td.Set(\"site_group_id\", scopeID)\n\t\tcase \"dcim.location\":\n\t\t\td.Set(\"location_id\", scopeID)\n\t\tcase \"dcim.region\":\n\t\t\td.Set(\"region_id\", scopeID)\n\t\t}\n\t}\n\n\tif result.CustomFields != nil {\n\t\td.Set(\"custom_fields\", flattenCustomFields(result.CustomFields))\n\t}\n\n\td.Set(tagsKey, getTagListFromNestedTagList(result.Tags))\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_cluster_group.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxClusterGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxClusterGroupRead,\n\t\tDescription: `:meta:subcategory:Virtualization:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"cluster_group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxClusterGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := virtualization.NewVirtualizationClusterGroupsListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Virtualization.VirtualizationClusterGroupsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one cluster group returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no cluster group found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.Set(\"cluster_group_id\", result.ID)\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_cluster_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxClusterGroupDataSource_basic(t *testing.T) {\n\ttestSlug := \"clstrgrp_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_cluster_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\ndata \"netbox_cluster_group\" \"test\" {\n  depends_on = [netbox_cluster_group.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster_group.test\", \"cluster_group_id\", \"netbox_cluster_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster_group.test\", \"id\", \"netbox_cluster_group.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_cluster_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxClusterDataSource_basic(t *testing.T) {\n\ttestSlug := \"clstr_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  cluster_group_id = netbox_cluster_group.test.id\n  site_id = netbox_site.test.id\n  comments = \"%[1]scomments\"\n  description = \"%[1]sdescription\"\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_region\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test_with_region\" {\n  name = \"%[1]s_with_region\"\n  cluster_type_id = netbox_cluster_type.test.id\n  cluster_group_id = netbox_cluster_group.test.id\n  region_id = netbox_region.test.id\n  comments = \"%[1]scomments\"\n  description = \"%[1]sdescription\"\n  tags = [netbox_tag.test.name]\n}\n\ndata \"netbox_cluster\" \"by_name\" {\n  name = netbox_cluster.test.name\n}\n\ndata \"netbox_cluster\" \"by_site_id\" {\n  site_id = netbox_cluster.test.site_id\n}\n\ndata \"netbox_cluster\" \"by_id\" {\n  id = netbox_cluster.test.id\n}\n\ndata \"netbox_cluster\" \"by_id_with_region\" {\n  id = netbox_cluster.test_with_region.id\n}\n\ndata \"netbox_cluster\" \"by_site_id_and_group_id\" {\n  site_id          = netbox_cluster.test.site_id\n  cluster_group_id = netbox_cluster.test.cluster_group_id\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_name\", \"id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_site_id\", \"id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_id\", \"id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_cluster.by_name\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_name\", \"cluster_type_id\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_name\", \"cluster_group_id\", \"netbox_cluster_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_cluster.by_name\", \"comments\", testName+\"comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_cluster.by_name\", \"description\", testName+\"description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_cluster.by_name\", \"scope_type\", \"dcim.site\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_name\", \"scope_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_name\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_id_with_region\", \"region_id\", \"netbox_region.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_cluster.by_name\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_cluster.by_name\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster.by_site_id_and_group_id\", \"id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_cluster_type.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxClusterType() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxClusterTypeRead,\n\t\tDescription: `:meta:subcategory:Virtualization:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"cluster_type_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxClusterTypeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := virtualization.NewVirtualizationClusterTypesListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Virtualization.VirtualizationClusterTypesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one cluster type returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no cluster type found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.Set(\"cluster_type_id\", result.ID)\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_cluster_type_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxClusterTypeDataSource_basic(t *testing.T) {\n\ttestSlug := \"clstrtyp_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\ndata \"netbox_cluster_type\" \"test\" {\n  depends_on = [netbox_cluster_type.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster_type.test\", \"cluster_type_id\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_cluster_type.test\", \"id\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_clusters.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxClusters() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxClustersRead,\n\t\tDescription: `:meta:subcategory:Virtualization:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"name_regex\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringIsValidRegExp,\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"clusters\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"cluster_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"cluster_type_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"cluster_group_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tenant_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site_group_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"location_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"region_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"scope_type\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"scope_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"comments\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"custom_fields\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttagsKey: tagsSchemaRead,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxClustersRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := virtualization.NewVirtualizationClustersListParams()\n\n\t// Get user limit (0 = fetch all)\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tvar tags []string\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"cluster_type_id\":\n\t\t\t\tparams.TypeID = &vString\n\t\t\tcase \"cluster_group_id\":\n\t\t\t\tparams.GroupID = &vString\n\t\t\tcase \"site_id\":\n\t\t\t\tparams.SiteID = &vString\n\t\t\tcase \"tag\":\n\t\t\t\ttags = append(tags, vString)\n\t\t\t\tparams.Tag = tags\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination (fetch all when name_regex is used)\n\tpaginationHelper := NewPaginationHelper(FetchAll)\n\tvar allClusters []*models.Cluster\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Virtualization.VirtualizationClustersList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch clusters at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallClusters = append(allClusters, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allClusters)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Apply name_regex filter\n\tvar filteredClusters []*models.Cluster\n\tif nameRegex, ok := d.GetOk(\"name_regex\"); ok {\n\t\tr := regexp.MustCompile(nameRegex.(string))\n\t\tfor _, cluster := range allClusters {\n\t\t\tif r.MatchString(*cluster.Name) {\n\t\t\t\tfilteredClusters = append(filteredClusters, cluster)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfilteredClusters = allClusters\n\t}\n\n\t// Apply user limit to filtered results\n\tif userLimit > 0 && int64(len(filteredClusters)) > userLimit {\n\t\tfilteredClusters = filteredClusters[:userLimit]\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, cluster := range filteredClusters {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"cluster_id\"] = cluster.ID\n\n\t\tif cluster.Name != nil {\n\t\t\tmapping[\"name\"] = *cluster.Name\n\t\t}\n\n\t\tif cluster.Type != nil {\n\t\t\tmapping[\"cluster_type_id\"] = cluster.Type.ID\n\t\t}\n\n\t\tif cluster.Group != nil {\n\t\t\tmapping[\"cluster_group_id\"] = cluster.Group.ID\n\t\t}\n\n\t\tif cluster.Tenant != nil {\n\t\t\tmapping[\"tenant_id\"] = cluster.Tenant.ID\n\t\t}\n\n\t\tif cluster.Description != \"\" {\n\t\t\tmapping[\"description\"] = cluster.Description\n\t\t}\n\n\t\tif cluster.Comments != \"\" {\n\t\t\tmapping[\"comments\"] = cluster.Comments\n\t\t}\n\n\t\tif cluster.ScopeType != nil && cluster.ScopeID != nil {\n\t\t\tmapping[\"scope_type\"] = *cluster.ScopeType\n\t\t\tmapping[\"scope_id\"] = *cluster.ScopeID\n\t\t\tswitch *cluster.ScopeType {\n\t\t\tcase \"dcim.site\":\n\t\t\t\tmapping[\"site_id\"] = *cluster.ScopeID\n\t\t\tcase \"dcim.sitegroup\":\n\t\t\t\tmapping[\"site_group_id\"] = *cluster.ScopeID\n\t\t\tcase \"dcim.location\":\n\t\t\t\tmapping[\"location_id\"] = *cluster.ScopeID\n\t\t\tcase \"dcim.region\":\n\t\t\t\tmapping[\"region_id\"] = *cluster.ScopeID\n\t\t\t}\n\t\t}\n\n\t\tif cluster.CustomFields != nil {\n\t\t\tmapping[\"custom_fields\"] = cluster.CustomFields\n\t\t}\n\n\t\tif cluster.Tags != nil {\n\t\t\tmapping[tagsKey] = getTagListFromNestedTagList(cluster.Tags)\n\t\t}\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"clusters\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_clusters_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxClustersDataSource_basic(t *testing.T) {\n\ttestSlug := \"clusters_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tdependencies := testAccNetboxClustersDataSourceDependencies(testName)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxClustersDataSourceFilterName(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.0.name\", testName+\"_0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.0.comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.0.description\", \"thisisadescription\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.cluster_type_id\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.cluster_group_id\", \"netbox_cluster_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxClustersDataSourceFilterClusterTypeID,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.#\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.cluster_type_id\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.name\", \"netbox_cluster.test0\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.1.name\", \"netbox_cluster.test1\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.2.name\", \"netbox_cluster.test2\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.3.name\", \"netbox_cluster.test3\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxClustersDataSourceFilterClusterGroupID,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.cluster_group_id\", \"netbox_cluster_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.name\", \"netbox_cluster.test0\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxClustersDataSourceFilterSiteID,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.name\", \"netbox_cluster.test0\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxClustersDataSourceNameRegex,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.name\", \"netbox_cluster.test2\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.1.name\", \"netbox_cluster.test3\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxClustersDataSourceLimit,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.test\", \"clusters.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_clusters.test\", \"clusters.0.cluster_type_id\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxClustersDataSource_tags(t *testing.T) {\n\ttestSlug := \"clusters_ds_tags\"\n\ttestName := testAccGetTestName(testSlug)\n\tdependencies := testAccNetboxClustersDataSourceDependenciesWithTags(testName)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxClustersDataSourceTagA(testName) + testAccNetboxClustersDataSourceTagB(testName) + testAccNetboxClustersDataSourceTagAB(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.tag-a\", \"clusters.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.tag-b\", \"clusters.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_clusters.tag-ab\", \"clusters.#\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxClustersDataSourceDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test0\" {\n  name             = \"%[1]s_0\"\n  cluster_type_id  = netbox_cluster_type.test.id\n  cluster_group_id = netbox_cluster_group.test.id\n  site_id          = netbox_site.test.id\n  tenant_id        = netbox_tenant.test.id\n  comments         = \"thisisacomment\"\n  description      = \"thisisadescription\"\n}\n\nresource \"netbox_cluster\" \"test1\" {\n  name            = \"%[1]s_1\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n\nresource \"netbox_cluster\" \"test2\" {\n  name            = \"%[1]s_2_regex\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n\nresource \"netbox_cluster\" \"test3\" {\n  name            = \"%[1]s_3_regex\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n`, testName)\n}\n\nfunc testAccNetboxClustersDataSourceDependenciesWithTags(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"servicea\" {\n  name = \"%[1]s_service-a\"\n}\n\nresource \"netbox_tag\" \"serviceb\" {\n  name = \"%[1]s_service-b\"\n}\n\nresource \"netbox_cluster\" \"test0\" {\n  name            = \"%[1]s_0\"\n  cluster_type_id = netbox_cluster_type.test.id\n  tags = [\n    netbox_tag.servicea.name,\n    netbox_tag.serviceb.name,\n  ]\n}\n\nresource \"netbox_cluster\" \"test1\" {\n  name            = \"%[1]s_1\"\n  cluster_type_id = netbox_cluster_type.test.id\n  tags = [\n    netbox_tag.servicea.name,\n  ]\n}\n\nresource \"netbox_cluster\" \"test2\" {\n  name            = \"%[1]s_2\"\n  cluster_type_id = netbox_cluster_type.test.id\n  tags = [\n    netbox_tag.serviceb.name,\n  ]\n}\n`, testName)\n}\n\nfunc testAccNetboxClustersDataSourceFilterName(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_clusters\" \"test\" {\n  filter {\n    name  = \"name\"\n    value = \"%[1]s_0\"\n  }\n}`, testName)\n}\n\nconst testAccNetboxClustersDataSourceFilterClusterTypeID = `\ndata \"netbox_clusters\" \"test\" {\n  filter {\n    name  = \"cluster_type_id\"\n    value = netbox_cluster_type.test.id\n  }\n}`\n\nconst testAccNetboxClustersDataSourceFilterClusterGroupID = `\ndata \"netbox_clusters\" \"test\" {\n  filter {\n    name  = \"cluster_group_id\"\n    value = netbox_cluster_group.test.id\n  }\n}`\n\nconst testAccNetboxClustersDataSourceFilterSiteID = `\ndata \"netbox_clusters\" \"test\" {\n  filter {\n    name  = \"site_id\"\n    value = netbox_site.test.id\n  }\n}`\n\nconst testAccNetboxClustersDataSourceNameRegex = `\ndata \"netbox_clusters\" \"test\" {\n  name_regex = \"test.*_regex\"\n}`\n\nconst testAccNetboxClustersDataSourceLimit = `\ndata \"netbox_clusters\" \"test\" {\n  limit = 1\n  filter {\n    name  = \"cluster_type_id\"\n    value = netbox_cluster_type.test.id\n  }\n}`\n\nfunc testAccNetboxClustersDataSourceTagA(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_clusters\" \"tag-a\" {\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s_service-a\"\n  }\n}`, testName)\n}\n\nfunc testAccNetboxClustersDataSourceTagB(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_clusters\" \"tag-b\" {\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s_service-b\"\n  }\n}`, testName)\n}\n\nfunc testAccNetboxClustersDataSourceTagAB(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_clusters\" \"tag-ab\" {\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s_service-a\"\n  }\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s_service-b\"\n  }\n}`, testName)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_config_context.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxConfigContext() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxConfigContextRead,\n\t\tDescription: `:meta:subcategory:Extras:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"weight\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"data\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"cluster_groups\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"cluster_types\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"clusters\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"device_types\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"locations\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"platforms\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"regions\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"roles\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"site_groups\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"sites\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"tenant_groups\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"tenants\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"tags\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxConfigContextRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := extras.NewExtrasConfigContextsListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Extras.ExtrasConfigContextsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one result. Specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no result\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"weight\", result.Weight)\n\n\tif result.Data != nil {\n\t\tif jsonArr, err := json.Marshal(result.Data); err == nil {\n\t\t\td.Set(\"data\", string(jsonArr))\n\t\t}\n\t} else {\n\t\td.Set(\"data\", nil)\n\t}\n\n\tclusterGroups := make([]int64, len(result.ClusterGroups))\n\tfor i, v := range result.ClusterGroups {\n\t\tclusterGroups[i] = int64(v.ID)\n\t}\n\td.Set(\"cluster_groups\", clusterGroups)\n\n\tclusterTypes := make([]int64, len(result.ClusterTypes))\n\tfor i, v := range result.ClusterTypes {\n\t\tclusterTypes[i] = int64(v.ID)\n\t}\n\td.Set(\"cluster_types\", clusterTypes)\n\n\tclusters := make([]int64, len(result.Clusters))\n\tfor i, v := range result.Clusters {\n\t\tclusters[i] = int64(v.ID)\n\t}\n\td.Set(\"clusters\", clusters)\n\n\tdeviceTypes := make([]int64, len(result.DeviceTypes))\n\tfor i, v := range result.DeviceTypes {\n\t\tdeviceTypes[i] = int64(v.ID)\n\t}\n\td.Set(\"device_types\", deviceTypes)\n\n\tlocations := make([]int64, len(result.Locations))\n\tfor i, v := range result.Locations {\n\t\tlocations[i] = int64(v.ID)\n\t}\n\td.Set(\"locations\", locations)\n\n\tplatforms := make([]int64, len(result.Platforms))\n\tfor i, v := range result.Platforms {\n\t\tplatforms[i] = int64(v.ID)\n\t}\n\td.Set(\"platforms\", platforms)\n\n\tregions := make([]int64, len(result.Regions))\n\tfor i, v := range result.Regions {\n\t\tregions[i] = int64(v.ID)\n\t}\n\td.Set(\"regions\", regions)\n\n\troles := make([]int64, len(result.Roles))\n\tfor i, v := range result.Roles {\n\t\troles[i] = int64(v.ID)\n\t}\n\td.Set(\"roles\", roles)\n\n\tsiteGroups := make([]int64, len(result.SiteGroups))\n\tfor i, v := range result.SiteGroups {\n\t\tsiteGroups[i] = int64(v.ID)\n\t}\n\td.Set(\"site_groups\", siteGroups)\n\n\tsites := make([]int64, len(result.Sites))\n\tfor i, v := range result.Sites {\n\t\tsites[i] = int64(v.ID)\n\t}\n\td.Set(\"sites\", sites)\n\n\ttenantGroups := make([]int64, len(result.TenantGroups))\n\tfor i, v := range result.TenantGroups {\n\t\ttenantGroups[i] = int64(v.ID)\n\t}\n\td.Set(\"tenant_groups\", tenantGroups)\n\n\ttenants := make([]int64, len(result.Tenants))\n\tfor i, v := range result.Tenants {\n\t\ttenants[i] = int64(v.ID)\n\t}\n\td.Set(\"tenants\", tenants)\n\n\ttags := make([]string, len(result.Tags))\n\tfor i, v := range result.Tags {\n\t\ttags[i] = string(v)\n\t}\n\td.Set(\"tags\", tags)\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_config_context_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxConfigContextDataSource_basic(t *testing.T) {\n\ttestSlug := \"cfct_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_config_context\" \"test\" {\n  name = \"%[1]s\"\n  weight = 1000\n  data = jsonencode({\"testkey\" = \"testval\"})\n}\ndata \"netbox_config_context\" \"test\" {\n  depends_on = [netbox_config_context.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_config_context.test\", \"id\", \"netbox_config_context.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_config_context.test\", \"weight\", \"netbox_config_context.test\", \"weight\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_config_context.test\", \"data\", \"netbox_config_context.test\", \"data\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_contact.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxContact() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxContactRead,\n\t\tDescription: `:meta:subcategory:Tenancy:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tComputed:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxContactRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := tenancy.NewTenancyContactsListParams()\n\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.Name = &name\n\t}\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Tenancy.TenancyContactsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one contact returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no contact found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\tif result.Group != nil {\n\t\td.Set(\"group_id\", result.Group.ID)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_contact_group.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxContactGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxContactGroupRead,\n\t\tDescription: `:meta:subcategory:Tenancy:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxContactGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := tenancy.NewTenancyContactGroupsListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Tenancy.TenancyContactGroupsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one contact group returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no contact group found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"description\", result.Description)\n\tif result.Parent != nil {\n\t\td.Set(\"parent_id\", result.Parent.ID)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_contact_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxContactGroupDataSource_basic(t *testing.T) {\n\ttestSlug := \"cntctgrp_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_contact_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\ndata \"netbox_contact_group\" \"test\" {\n  name = netbox_contact_group.test.name\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_contact_group.test\", \"id\", \"netbox_contact_group.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_contact_role.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxContactRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxContactRoleRead,\n\t\tDescription: `:meta:subcategory:Tenancy:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tComputed:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxContactRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := tenancy.NewTenancyContactRolesListParams()\n\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.Name = &name\n\t}\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Tenancy.TenancyContactRolesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one contact role returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no contact role found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_contact_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxContactRoleDataSource_basic(t *testing.T) {\n\ttestSlug := \"cntctrl_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_contact_role\" \"test\" {\n  name = \"%[1]s\"\n}\n\ndata \"netbox_contact_role\" \"by_name\" {\n  name = netbox_contact_role.test.name\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_contact_role.by_name\", \"id\", \"netbox_contact_role.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_contact_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxContactDataSource_basic(t *testing.T) {\n\ttestSlug := \"cntct_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_contact\" \"test\" {\n  name = \"%[1]s\"\n}\n\ndata \"netbox_contact\" \"by_name\" {\n  depends_on = [netbox_contact.test]\n  name = \"%[1]s\"\n}\n\ndata \"netbox_contact\" \"by_slug\" {\n  depends_on = [netbox_contact.test]\n  slug = \"%[1]s\"\n}\n\ndata \"netbox_contact\" \"by_description\" {\n  depends_on = [netbox_contact.test]\n  name = \"%[1]s\"\n  description = \"%[1]s\"\n}\n\ndata \"netbox_contact\" \"by_both\" {\n  depends_on = [netbox_contact.test]\n  name = \"%[1]s\"\n  slug = \"%[1]s\"\n  description = \"%[1]s\"\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_contact.by_name\", \"id\", \"netbox_contact.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_contact.by_slug\", \"id\", \"netbox_contact.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_contact.by_description\", \"id\", \"netbox_contact.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_contact.by_both\", \"id\", \"netbox_contact.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_interfaces.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxDeviceInterfaces() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxDeviceInterfaceRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"name_regex\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringIsValidRegExp,\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"interfaces\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"enabled\": {\n\t\t\t\t\t\t\tType:     schema.TypeBool,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mac_address\": {\n\t\t\t\t\t\t\tType:        schema.TypeString,\n\t\t\t\t\t\t\tComputed:    true,\n\t\t\t\t\t\t\tDescription: \"The MAC address as string from the first MAC address assigned to this interface, if any.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mac_addresses\": {\n\t\t\t\t\t\t\tType:     schema.TypeSet,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"mac_address\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mode\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mtu\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tag_ids\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tagged_vlans\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"vid\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t// Do as a TypeList due to limitation of TypeMap\n\t\t\t\t\t\t\"untagged_vlan\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"vid\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"device_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxDeviceInterfaceRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := dcim.NewDcimInterfacesListParams()\n\n\t// Get user limit (0 = fetch all)\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tfilterParams := filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"mac_address\":\n\t\t\t\tparams.MacAddress = &vString\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"tag\":\n\t\t\t\tparams.Tag = []string{vString} // TODO: switch schema to list?\n\t\t\tcase \"device_id\":\n\t\t\t\tparams.DeviceID = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination (fetch all when name_regex is used)\n\tpaginationHelper := NewPaginationHelper(FetchAll)\n\tvar allInterfaces []*models.Interface\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Dcim.DcimInterfacesList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch interfaces at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallInterfaces = append(allInterfaces, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allInterfaces)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Apply name_regex filter\n\tvar filteredInterfaces []*models.Interface\n\tif nameRegex, ok := d.GetOk(\"name_regex\"); ok {\n\t\tr := regexp.MustCompile(nameRegex.(string))\n\t\tfor _, dcimInterface := range allInterfaces {\n\t\t\tif r.MatchString(*dcimInterface.Name) {\n\t\t\t\tfilteredInterfaces = append(filteredInterfaces, dcimInterface)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfilteredInterfaces = allInterfaces\n\t}\n\n\t// Apply user limit to filtered results\n\tif userLimit > 0 && int64(len(filteredInterfaces)) > userLimit {\n\t\tfilteredInterfaces = filteredInterfaces[:userLimit]\n\t}\n\n\tif len(filteredInterfaces) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredInterfaces {\n\t\tmapping := make(map[string]interface{})\n\t\tmapping[\"id\"] = v.ID\n\t\tif v.Description != \"\" {\n\t\t\tmapping[\"description\"] = v.Description\n\t\t}\n\t\tmapping[\"enabled\"] = v.Enabled\n\t\tif v.MacAddresses != nil {\n\t\t\tvar mac_addresses []map[string]interface{}\n\t\t\tfor i, mac := range v.MacAddresses {\n\t\t\t\tmac_address := make(map[string]interface{})\n\t\t\t\t// We just set the first mac address in the `mac_address` attribute\n\t\t\t\tif i == 0 {\n\t\t\t\t\tmapping[\"mac_address\"] = v.MacAddresses[i].MacAddress\n\t\t\t\t}\n\t\t\t\tmac_address[\"id\"] = mac.ID\n\t\t\t\tmac_address[\"description\"] = mac.Description\n\t\t\t\tmac_address[\"mac_address\"] = mac.MacAddress\n\t\t\t\tmac_addresses = append(mac_addresses, mac_address)\n\t\t\t}\n\t\t\tmapping[\"mac_addresses\"] = mac_addresses\n\t\t}\n\t\tif v.Mode != nil {\n\t\t\tmapping[\"mode\"] = map[string]string{\n\t\t\t\t\"label\": *v.Mode.Label,\n\t\t\t\t\"value\": *v.Mode.Value,\n\t\t\t}\n\t\t}\n\t\tif v.Mtu != nil {\n\t\t\tmapping[\"mtu\"] = *v.Mtu\n\t\t}\n\t\tif v.Name != nil {\n\t\t\tmapping[\"name\"] = *v.Name\n\t\t}\n\t\tif v.TaggedVlans != nil {\n\t\t\tmapping[\"tagged_vlans\"] = flattenVlanAttributes(v.TaggedVlans)\n\t\t}\n\t\tif v.Tags != nil {\n\t\t\tvar tags []int64\n\t\t\tfor _, t := range v.Tags {\n\t\t\t\ttags = append(tags, t.ID)\n\t\t\t}\n\t\t\tmapping[\"tag_ids\"] = tags\n\t\t}\n\t\tif v.UntaggedVlan != nil {\n\t\t\tvlanSlice := []*models.NestedVLAN{v.UntaggedVlan}\n\t\t\tmapping[\"untagged_vlan\"] = flattenVlanAttributes(vlanSlice)\n\t\t}\n\n\t\tif v.Type != nil && v.Type.Value != nil {\n\t\t\tmapping[\"type\"] = *v.Type.Value\n\t\t}\n\n\t\tmapping[\"device_id\"] = v.Device.ID\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"interfaces\", s)\n}\n\n/*\n\nTODO: maybe separate this function from both VM Interfaces and DCIM Interfaces?\n\nfunc flattenVlanAttributes(vlans []*models.NestedVLAN) []map[string]interface{} {\n\tvar mappedVlans []map[string]interface{}\n\tfor _, vlan := range vlans {\n\t\tv := *vlan\n\t\tmappedVlan := map[string]interface{}{\n\t\t\t\"id\":   v.ID,\n\t\t\t\"vid\":  *v.Vid,\n\t\t\t\"name\": *v.Name,\n\t\t}\n\t\tmappedVlans = append(mappedVlans, mappedVlan)\n\t}\n\treturn mappedVlans\n}\n*/\n"
  },
  {
    "path": "netbox/data_source_netbox_device_interfaces_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxDeviceInterfacesDataSource_basic(t *testing.T) {\n\ttestSlug := \"dev_ifaces_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tdependencies := testAccNetboxDeviceInterfacesDataSourceDependencies(testName)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + `\ndata \"netbox_device_interfaces\" \"by_name\" {\n  filter {\n    name = \"name\"\n    value  = netbox_device_interface.test.name\n  }\n}\n\ndata \"netbox_device_interfaces\" \"by_device_id\" {\n  filter {\n    name = \"device_id\"\n    value  = netbox_device.test.id\n  }\n}\n\ndata \"netbox_device_interfaces\" \"by_mac_address\" {\n  filter {\n    name = \"mac_address\"\n    value  = netbox_mac_address.test.mac_address\n  }\n}\n\ndata \"netbox_device_interfaces\" \"by_tag\" {\n  filter {\n    name = \"tag\"\n    value  = netbox_tag.test.name\n  }\n}\n`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_interfaces.by_name\", \"interfaces.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_interfaces.by_name\", \"interfaces.0.type\", \"1000base-t\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_interfaces.by_name\", \"interfaces.0.name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_interfaces.by_name\", \"interfaces.0.enabled\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_device_interfaces.by_name\", \"interfaces.0.device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_interfaces.by_device_id\", \"interfaces.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_interfaces.by_mac_address\", \"interfaces.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_device_interfaces.by_mac_address\", \"interfaces.0.mac_addresses.0.id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_device_interfaces.by_mac_address\", \"interfaces.0.mac_addresses.0.mac_address\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_device_interfaces.by_mac_address\", \"interfaces.0.mac_addresses.0.description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_interfaces.by_tag\", \"interfaces.#\", \"2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxDeviceInterfacesDataSourceDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_interface\" \"test\" {\n  name = \"%[1]s\"\n  device_id = netbox_device.test.id\n  tags = [netbox_tag.test.name]\n  type = \"1000base-t\"\n}\n\nresource \"netbox_device_interface\" \"test2\" {\n  name = \"%[1]s_two\"\n  device_id = netbox_device.test.id\n  tags = [netbox_tag.test.name]\n  type = \"1000base-t\"\n}\n\nresource \"netbox_mac_address\" \"test\" {\n  mac_address = \"F4:02:BA:7F:FD:F8\"\n  device_interface_id = netbox_device_interface.test.id\n  description = \"%[1]s\"\n}\n`, testName)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_power_ports.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxDevicePowerPorts() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxDevicePowerPortRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"name_regex\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringIsValidRegExp,\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"power_ports\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tag_ids\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"device_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"module_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"maximum_draw\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"allocated_draw\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxDevicePowerPortRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := dcim.NewDcimPowerPortsListParams()\n\n\t// Get user limit (0 = fetch all)\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"tag\":\n\t\t\t\tparams.Tag = []string{vString} //TODO: switch schema to list?\n\t\t\tcase \"device_id\":\n\t\t\t\tparams.DeviceID = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination (fetch all when name_regex is used)\n\tpaginationHelper := NewPaginationHelper(FetchAll)\n\tvar allPowerPorts []*models.PowerPort\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Dcim.DcimPowerPortsList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch power ports at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallPowerPorts = append(allPowerPorts, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allPowerPorts)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Apply name_regex filter\n\tvar filteredPowerPorts []*models.PowerPort\n\tif nameRegex, ok := d.GetOk(\"name_regex\"); ok {\n\t\tr, err := regexp.Compile(nameRegex.(string))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to compile name regex: %w\", err)\n\t\t}\n\t\tfor _, port := range allPowerPorts {\n\t\t\tif r.MatchString(*port.Name) {\n\t\t\t\tfilteredPowerPorts = append(filteredPowerPorts, port)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfilteredPowerPorts = allPowerPorts\n\t}\n\n\t// Apply user limit to filtered results\n\tif userLimit > 0 && int64(len(filteredPowerPorts)) > userLimit {\n\t\tfilteredPowerPorts = filteredPowerPorts[:userLimit]\n\t}\n\n\tif len(filteredPowerPorts) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredPowerPorts {\n\t\tvar mapping = make(map[string]interface{})\n\t\tmapping[\"id\"] = v.ID\n\t\tif v.Description != \"\" {\n\t\t\tmapping[\"description\"] = v.Description\n\t\t}\n\t\tif v.Name != nil {\n\t\t\tmapping[\"name\"] = *v.Name\n\t\t}\n\t\tif v.Tags != nil {\n\t\t\tvar tags []int64\n\t\t\tfor _, t := range v.Tags {\n\t\t\t\ttags = append(tags, t.ID)\n\t\t\t}\n\t\t\tmapping[\"tag_ids\"] = tags\n\t\t}\n\n\t\tmapping[\"device_id\"] = v.Device.ID\n\t\tif v.Module != nil {\n\t\t\tmapping[\"module_id\"] = v.Module.ID\n\t\t}\n\n\t\tif v.Type != nil {\n\t\t\tmapping[\"type\"] = v.Type.Value\n\t\t}\n\n\t\tif v.MaximumDraw != nil {\n\t\t\tmapping[\"maximum_draw\"] = *v.MaximumDraw\n\t\t}\n\t\tif v.AllocatedDraw != nil {\n\t\t\tmapping[\"allocated_draw\"] = *v.AllocatedDraw\n\t\t}\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"power_ports\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_power_ports_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxDevicePowerportsDataSource_basic(t *testing.T) {\n\ttestSlug := \"dev_powerports_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tdependencies := testAccNetboxDevicePowerportsDataSourceDependencies(testName)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + fmt.Sprintf(`\ndata \"netbox_device_power_ports\" \"by_name\" {\n  depends_on = [\n    netbox_device_power_port.test,\n    netbox_device_power_port.test2,\n  ]\n\n  filter {\n    name = \"name\"\n    value  = \"%[1]s\"\n  }\n}\n\ndata \"netbox_device_power_ports\" \"by_device_id\" {\n  depends_on = [\n    netbox_device_power_port.test,\n    netbox_device_power_port.test2,\n  ]\n\n  filter {\n    name = \"device_id\"\n    value  = netbox_device.test.id\n  }\n}\n\ndata \"netbox_device_power_ports\" \"by_tag\" {\n  depends_on = [\n    netbox_device_power_port.test,\n    netbox_device_power_port.test2,\n  ]\n\n  filter {\n    name = \"tag\"\n    value  = netbox_tag.test.name\n  }\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_power_ports.by_name\", \"power_ports.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_power_ports.by_name\", \"power_ports.0.name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_power_ports.by_name\", \"power_ports.0.type\", \"iec-60309-3p-n-e-9h\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_device_power_ports.by_name\", \"power_ports.0.device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_power_ports.by_device_id\", \"power_ports.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_power_ports.by_tag\", \"power_ports.#\", \"2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxDevicePowerportsDataSourceDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_power_port\" \"test\" {\n  name = \"%[1]s\"\n  device_id = netbox_device.test.id\n  type = \"iec-60309-3p-n-e-9h\"\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_power_port\" \"test2\" {\n  name = \"%[1]s_two\"\n  device_id = netbox_device.test.id\n  tags = [netbox_tag.test.name]\n}\n\n`, testName)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_render_config.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxDeviceRenderConfig() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxDeviceRenderConfigRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):Render the configuration template assigned to a device using the device's config context.`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: \"The ID of the device to render configuration for.\",\n\t\t\t},\n\t\t\t\"content\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tComputed:    true,\n\t\t\t\tDescription: \"The rendered configuration content.\",\n\t\t\t},\n\t\t\t\"config_template_id\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tComputed:    true,\n\t\t\t\tDescription: \"The ID of the config template that was used for rendering.\",\n\t\t\t},\n\t\t\t\"config_template_name\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tComputed:    true,\n\t\t\t\tDescription: \"The name of the config template that was used for rendering.\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxDeviceRenderConfigRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdeviceID := int64(d.Get(\"device_id\").(int))\n\n\tparams := dcim.NewDcimDevicesRenderConfigParams().WithID(deviceID)\n\n\tres, err := api.Dcim.DcimDevicesRenderConfig(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresult := res.GetPayload()\n\n\td.SetId(strconv.FormatInt(deviceID, 10))\n\td.Set(\"content\", result.Content)\n\n\tif result.Configtemplate != nil {\n\t\td.Set(\"config_template_id\", result.Configtemplate.ID)\n\t\td.Set(\"config_template_name\", result.Configtemplate.Name)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_render_config_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxDeviceRenderConfigDataSource_basic(t *testing.T) {\n\ttestSlug := \"device_render_cfg\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_config_template\" \"test\" {\n  name = \"%[1]s\"\n  template_code = \"hostname={{ device.name }}\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  role_id = netbox_device_role.test.id\n  config_template_id = netbox_config_template.test.id\n}\n\ndata \"netbox_device_render_config\" \"test\" {\n  depends_on = [netbox_device.test]\n  device_id = netbox_device.test.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_device_render_config.test\", \"id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_render_config.test\", \"content\", fmt.Sprintf(\"hostname=%s\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_device_render_config.test\", \"config_template_id\", \"netbox_config_template.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_render_config.test\", \"config_template_name\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_role.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxDeviceRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxDeviceRoleRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchemaRead,\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxDeviceRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := dcim.NewDcimDeviceRolesListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Dcim.DcimDeviceRolesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one device role returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no device role found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"color_hex\", result.Color)\n\td.Set(tagsKey, getTagListFromNestedTagList(result.Tags))\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxDeviceRoleDataSource_basic(t *testing.T) {\n\ttestSlug := \"dvrl_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n  tags = [netbox_tag.test.name]\n}\n\ndata \"netbox_device_role\" \"test\" {\n  depends_on = [netbox_device_role.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_device_role.test\", \"id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_role.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_role.test\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_type.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxDeviceType() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxDeviceTypeRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"is_full_depth\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"manufacturer\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"manufacturer_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"model\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"part_number\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"subdevice_role\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"u_height\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxDeviceTypeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := dcim.NewDcimDeviceTypesListParams()\n\n\tparams.Limit = int64ToPtr(2)\n\tif manufacturer, ok := d.Get(\"manufacturer\").(string); ok && manufacturer != \"\" {\n\t\tparams.Manufacturer = &manufacturer\n\t}\n\tif model, ok := d.Get(\"model\").(string); ok && model != \"\" {\n\t\tparams.Model = &model\n\t}\n\tif part, ok := d.Get(\"part_number\").(string); ok && part != \"\" {\n\t\tparams.PartNumber = &part\n\t}\n\tif slug, ok := d.Get(\"slug\").(string); ok && slug != \"\" {\n\t\tparams.Slug = &slug\n\t}\n\n\tres, err := api.Dcim.DcimDeviceTypesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one device type returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no device type found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"is_full_depth\", result.IsFullDepth)\n\td.Set(\"manufacturer_id\", result.Manufacturer.ID)\n\td.Set(\"model\", result.Model)\n\td.Set(\"part_number\", result.PartNumber)\n\tif result.SubdeviceRole != nil && result.SubdeviceRole.Value != nil {\n\t\td.Set(\"subdevice_role\", *result.SubdeviceRole.Value)\n\t} else {\n\t\td.Set(\"subdevice_role\", \"\")\n\t}\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"u_height\", result.UHeight)\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_device_type_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxDeviceTypeDataSource_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"ds_dv_tp\")\n\tsetUp := testAccNetboxDeviceTypeSetUp(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"slug\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + testAccNetboxDeviceTypeDataNoResult,\n\t\t\t\tExpectError: regexp.MustCompile(\"no device type found matching filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxDeviceTypeDataByModel(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_type.test\", \"slug\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxDeviceTypeDataCombo(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_type.test\", \"slug\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxDeviceTypeDataBySlug(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_type.test\", \"model\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_device_type.test\", \"part_number\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_device_type.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_device_type.test\", \"subdevice_role\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_device_type.test\", \"is_full_depth\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_device_type.test\", \"u_height\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxDeviceTypeSetUp(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n\tname = \"%[1]s\"\n}\nresource \"netbox_device_type\" \"test\" {\n\tmanufacturer_id = netbox_manufacturer.test.id\n\tmodel = \"%[1]s\"\n\tpart_number = \"%[1]s\"\n\tsubdevice_role = \"parent\"\n}`, testName)\n}\n\nconst testAccNetboxDeviceTypeDataNoResult = `\ndata \"netbox_device_type\" \"no_result\" {\n\tmodel = \"_no_result_\"\n}`\n\nfunc testAccNetboxDeviceTypeDataByModel(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_device_type\" \"test\" {\n\tmodel = \"%[1]s\"\n}`, testName)\n}\n\nfunc testAccNetboxDeviceTypeDataCombo(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_device_type\" \"test\" {\n\tmanufacturer = \"%[1]s\"\n\tpart_number = \"%[1]s\"\n}`, testName)\n}\n\nfunc testAccNetboxDeviceTypeDataBySlug(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_device_type\" \"test\" {\n\tslug = \"%[1]s\"\n}`, testName)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_devices.go",
    "content": "// Copyright (c) 2022 Cisco Systems, Inc. and its affiliates\n// All rights reserved.\n\npackage netbox\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxDevices() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxDevicesRead,\n\t\tDescription: \":meta:subcategory:Data Center Inventory Management (DCIM):\",\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"name_regex\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringIsValidRegExp,\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"devices\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"asset_tag\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"cluster_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"comments\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"config_context\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"local_context_data\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"custom_fields\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"device_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"device_type_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"location_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"manufacturer_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"model\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"platform_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tenant_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"serial\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"rack_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"rack_face\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"rack_position\": {\n\t\t\t\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"primary_ipv4\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"primary_ipv6\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"oob_ip\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tags\": tagsSchemaRead,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxDevicesRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := dcim.NewDcimDevicesListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limit, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limit.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tswitch k {\n\t\t\tcase \"asset_tag\":\n\t\t\t\tvar assetTagString = v.(string)\n\t\t\t\tparams.AssetTag = &assetTagString\n\t\t\tcase \"cluster_id\":\n\t\t\t\tvar clusterString = v.(string)\n\t\t\t\tparams.ClusterID = &clusterString\n\t\t\tcase \"device_type_id\":\n\t\t\t\tvar deviceTypeIDString = v.(string)\n\t\t\t\tparams.DeviceTypeID = &deviceTypeIDString\n\t\t\tcase \"name\":\n\t\t\t\tvar nameString = v.(string)\n\t\t\t\tparams.Name = &nameString\n\t\t\tcase \"region\":\n\t\t\t\tvar regionString = v.(string)\n\t\t\t\tparams.Region = &regionString\n\t\t\tcase \"role_id\":\n\t\t\t\tvar roleIDString = v.(string)\n\t\t\t\tparams.RoleID = &roleIDString\n\t\t\tcase \"site_id\":\n\t\t\t\tvar siteIDString = v.(string)\n\t\t\t\tparams.SiteID = &siteIDString\n\t\t\tcase \"location_id\":\n\t\t\t\tvar locationIDString = v.(string)\n\t\t\t\tparams.LocationID = &locationIDString\n\t\t\tcase \"rack_id\":\n\t\t\t\tvar rackIDString = v.(string)\n\t\t\t\tparams.RackID = &rackIDString\n\t\t\tcase \"tenant_id\":\n\t\t\t\tvar tenantIDString = v.(string)\n\t\t\t\tparams.TenantID = &tenantIDString\n\t\t\tcase \"tags\":\n\t\t\t\tvar tagsString = v.(string)\n\t\t\t\tparams.Tag = strings.Split(tagsString, \",\")\n\t\t\tcase \"status\":\n\t\t\t\tvar statusString = v.(string)\n\t\t\t\tparams.Status = &statusString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination (fetch all when name_regex is used)\n\tpaginationHelper := NewPaginationHelper(FetchAll)\n\tvar allDevices []*models.DeviceWithConfigContext\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Dcim.DcimDevicesList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch devices at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallDevices = append(allDevices, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allDevices)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Apply name_regex filter to all fetched devices\n\tvar filteredDevices []*models.DeviceWithConfigContext\n\tif nameRegex, ok := d.GetOk(\"name_regex\"); ok {\n\t\tr := regexp.MustCompile(nameRegex.(string))\n\t\tfor _, device := range allDevices {\n\t\t\tif r.MatchString(*device.Name) {\n\t\t\t\tfilteredDevices = append(filteredDevices, device)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfilteredDevices = allDevices\n\t}\n\n\t// Apply user limit to filtered results\n\tif userLimit > 0 && int64(len(filteredDevices)) > userLimit {\n\t\tfilteredDevices = filteredDevices[:userLimit]\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, device := range filteredDevices {\n\t\tvar mapping = make(map[string]interface{})\n\t\tif device.AssetTag != nil {\n\t\t\tmapping[\"asset_tag\"] = *device.AssetTag\n\t\t}\n\t\tif device.Cluster != nil {\n\t\t\tmapping[\"cluster_id\"] = device.Cluster.ID\n\t\t}\n\t\tif device.Comments != \"\" {\n\t\t\tmapping[\"comments\"] = device.Comments\n\t\t}\n\t\tif device.Description != \"\" {\n\t\t\tmapping[\"description\"] = device.Description\n\t\t}\n\t\tif device.ConfigContext != nil {\n\t\t\tif configContext, err := json.Marshal(device.ConfigContext); err == nil {\n\t\t\t\tmapping[\"config_context\"] = string(configContext)\n\t\t\t}\n\t\t}\n\t\tif device.LocalContextData != nil {\n\t\t\tif localContextData, err := json.Marshal(device.LocalContextData); err == nil {\n\t\t\t\tmapping[\"local_context_data\"] = string(localContextData)\n\t\t\t}\n\t\t}\n\t\tmapping[\"device_id\"] = device.ID\n\t\tif device.DeviceType != nil {\n\t\t\tmapping[\"device_type_id\"] = device.DeviceType.ID\n\t\t}\n\t\tif device.DeviceType.Manufacturer != nil {\n\t\t\tmapping[\"manufacturer_id\"] = device.DeviceType.Manufacturer.ID\n\t\t}\n\t\tif device.DeviceType.Model != nil {\n\t\t\tmapping[\"model\"] = *device.DeviceType.Model\n\t\t}\n\t\tif device.Name != nil {\n\t\t\tmapping[\"name\"] = *device.Name\n\t\t}\n\t\tif device.Location != nil {\n\t\t\tmapping[\"location_id\"] = device.Location.ID\n\t\t}\n\t\tif device.Platform != nil {\n\t\t\tmapping[\"platform_id\"] = device.Platform.ID\n\t\t}\n\t\tif device.Site != nil {\n\t\t\tmapping[\"site_id\"] = device.Site.ID\n\t\t}\n\t\tif device.Tenant != nil {\n\t\t\tmapping[\"tenant_id\"] = device.Tenant.ID\n\t\t}\n\t\tif device.Role != nil {\n\t\t\tmapping[\"role_id\"] = device.Role.ID\n\t\t}\n\t\tif device.Serial != \"\" {\n\t\t\tmapping[\"serial\"] = device.Serial\n\t\t}\n\t\tif device.Status != nil {\n\t\t\tmapping[\"status\"] = *device.Status.Value\n\t\t}\n\t\tif device.CustomFields != nil {\n\t\t\tmapping[\"custom_fields\"] = flattenCustomFields(device.CustomFields)\n\t\t}\n\t\tif device.Rack != nil {\n\t\t\tmapping[\"rack_id\"] = device.Rack.ID\n\t\t}\n\t\tif device.Position != nil {\n\t\t\tmapping[\"rack_position\"] = device.Position\n\t\t}\n\t\tif device.Face != nil {\n\t\t\tmapping[\"rack_face\"] = device.Face.Value\n\t\t}\n\t\tif device.Tags != nil {\n\t\t\tmapping[\"tags\"] = getTagListFromNestedTagList(device.Tags)\n\t\t}\n\t\tif device.PrimaryIp4 != nil {\n\t\t\tip, _, err := net.ParseCIDR(*device.PrimaryIp4.Address)\n\t\t\tif err == nil {\n\t\t\t\tprimaryIPv4 := ip.String()\n\t\t\t\tmapping[\"primary_ipv4\"] = &primaryIPv4\n\t\t\t}\n\t\t}\n\t\tif device.PrimaryIp6 != nil {\n\t\t\tip, _, err := net.ParseCIDR(*device.PrimaryIp6.Address)\n\t\t\tif err == nil {\n\t\t\t\tprimaryIPv6 := ip.String()\n\t\t\t\tmapping[\"primary_ipv6\"] = &primaryIPv6\n\t\t\t}\n\t\t}\n\t\tif device.OobIP != nil {\n\t\t\tip, _, err := net.ParseCIDR(*device.OobIP.Address)\n\t\t\tif err == nil {\n\t\t\t\tOobIP := ip.String()\n\t\t\t\tmapping[\"oob_ip\"] = &OobIP\n\t\t\t}\n\t\t}\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"devices\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_devices_pagination_test.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\n// TestDataSourceNetboxDevicesPagination verifies that the devices data source fetches\n// all pages when total results exceed the page size, using a mock HTTP server.\n//\n// Without pagination the data source would return at most DefaultPageSize items;\n// this test uses 130 items (100 + 30, not divisible by page size) so the last page\n// is always partial, exercising the boundary condition.\nfunc TestDataSourceNetboxDevicesPagination(t *testing.T) {\n\tconst totalDevices = 130\n\n\trequestCount := 0\n\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path != \"/api/dcim/devices/\" {\n\t\t\thttp.NotFound(w, r)\n\t\t\treturn\n\t\t}\n\n\t\trequestCount++\n\n\t\toffset, _ := strconv.Atoi(r.URL.Query().Get(\"offset\"))\n\t\tlimit := int(DefaultPageSize)\n\t\tif s := r.URL.Query().Get(\"limit\"); s != \"\" {\n\t\t\tlimit, _ = strconv.Atoi(s)\n\t\t}\n\n\t\tend := offset + limit\n\t\tif end > totalDevices {\n\t\t\tend = totalDevices\n\t\t}\n\n\t\tvar nextURL interface{}\n\t\tif end < totalDevices {\n\t\t\tnextURL = fmt.Sprintf(\"http://%s/api/dcim/devices/?limit=%d&offset=%d\", r.Host, limit, end)\n\t\t}\n\n\t\tresults := make([]map[string]interface{}, 0, end-offset)\n\t\tfor i := offset; i < end; i++ {\n\t\t\tresults = append(results, minimalDeviceJSON(i+1, fmt.Sprintf(\"device-%d\", i+1)))\n\t\t}\n\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tjson.NewEncoder(w).Encode(map[string]interface{}{\n\t\t\t\"count\":    totalDevices,\n\t\t\t\"next\":     nextURL,\n\t\t\t\"previous\": nil,\n\t\t\t\"results\":  results,\n\t\t})\n\t}))\n\tdefer ts.Close()\n\n\tcfg := Config{APIToken: \"test-token\", ServerURL: ts.URL}\n\tclient, err := cfg.Client()\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create client: %v\", err)\n\t}\n\n\tstate := &providerState{NetBoxAPI: client}\n\td := schema.TestResourceDataRaw(t, dataSourceNetboxDevices().Schema, map[string]interface{}{})\n\n\tif err := dataSourceNetboxDevicesRead(d, state); err != nil {\n\t\tt.Fatalf(\"dataSourceNetboxDevicesRead returned error: %v\", err)\n\t}\n\n\tdevices := d.Get(\"devices\").([]interface{})\n\tif len(devices) != totalDevices {\n\t\tt.Errorf(\"got %d devices, want %d (pagination likely broken)\", len(devices), totalDevices)\n\t}\n\tif requestCount < 2 {\n\t\tt.Errorf(\"expected multiple API requests (pagination), got %d\", requestCount)\n\t}\n}\n\n// minimalDeviceJSON returns the minimum fields required by the go-netbox swagger\n// validator for a DeviceWithConfigContext response item.\nfunc minimalDeviceJSON(id int, name string) map[string]interface{} {\n\treturn map[string]interface{}{\n\t\t\"id\":   id,\n\t\t\"name\": name,\n\t\t\"device_type\": map[string]interface{}{\n\t\t\t\"id\":    1,\n\t\t\t\"model\": \"test-model\",\n\t\t\t\"slug\":  \"test-model\",\n\t\t\t\"manufacturer\": map[string]interface{}{\n\t\t\t\t\"id\":   1,\n\t\t\t\t\"name\": \"test-manufacturer\",\n\t\t\t\t\"slug\": \"test-manufacturer\",\n\t\t\t},\n\t\t},\n\t\t\"role\": map[string]interface{}{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"test-role\",\n\t\t\t\"slug\": \"test-role\",\n\t\t},\n\t\t\"site\": map[string]interface{}{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"test-site\",\n\t\t\t\"slug\": \"test-site\",\n\t\t},\n\t\t\"tags\": []interface{}{},\n\t}\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_devices_test.go",
    "content": "// Copyright (c) 2022 Cisco Systems, Inc. and its affiliates\n// All rights reserved.\n\npackage netbox\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxDevicesDataSource_basic(t *testing.T) {\n\ttestSlug := \"devices_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestLocalContextData, _ := json.Marshal(map[string]string{\"testkey0\": \"testvalue0\"})\n\tdependencies := testAccNetboxDeviceDataSourceDependencies(testName)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxDeviceDataSourceFilterName(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.name\", testName+\"_0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.comments\", \"this is also a comment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.description\", \"this is also a description\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.device_type_id\", \"netbox_device_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.serial\", \"ABCDEF0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.status\", \"staged\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.local_context_data\", string(testLocalContextData)),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxDeviceDataSourceFilterTenant,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.#\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.primary_ipv4\", \"10.0.0.60\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.name\", \"netbox_device.test0\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.1.name\", \"netbox_device.test1\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.2.name\", \"netbox_device.test2\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.3.name\", \"netbox_device.test3\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxDeviceDataSourceFilterRole,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.#\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.1.role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.name\", \"netbox_device.test0\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.1.name\", \"netbox_device.test1\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.2.name\", \"netbox_device.test2\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.3.name\", \"netbox_device.test3\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxDeviceDataSourceNameRegex(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.name\", \"netbox_device.test2\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.1.name\", \"netbox_device.test3\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxDeviceDataSourceLimit,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetBoxDeviceDataSourceFilterTagsAndStatus,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.tag_devices\", \"devices.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.tag_devices\", \"devices.0.tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.tag_devices\", \"devices.0.status\", \"staged\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetBoxDeviceDataSourceMultipleTagsFilter,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.multiple_filter_devices\", \"devices.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.multiple_filter_devices\", \"devices.0.tags.#\", \"2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxDeviceDataSourceDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_location\" \"test\" {\n  name = \"%[1]s\"\n  site_id =netbox_site.test.id\n}\n\nresource \"netbox_rack_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_rack\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  status = \"reserved\"\n  width = 19\n  u_height = 48\n  tenant_id = netbox_tenant.test.id\n  location_id = netbox_location.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_tag\" \"test_b\" {\n  name = \"%[1]sb\"\n}\n\nresource \"netbox_tag\" \"test_c\" {\n  name = \"%[1]sc\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_interface\" \"test\" {\n  name      = \"eth0\"\n  device_id = netbox_device.test0.id\n  type      = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"test\" {\n  ip_address   = \"10.0.0.60/24\"\n  status       = \"active\"\n  interface_id = netbox_device_interface.test.id\n  object_type  = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4\" {\n  device_id     = netbox_device.test0.id\n  ip_address_id = netbox_ip_address.test.id\n}\n\nresource \"netbox_device\" \"test0\" {\n  name = \"%[1]s_0\"\n  comments = \"this is also a comment\"\n  description = \"this is also a description\"\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  serial = \"ABCDEF0\"\n  status = \"staged\"\n  tags = [netbox_tag.test_a.name]\n  local_context_data = jsonencode({\"testkey0\"=\"testvalue0\"})\n}\n\nresource \"netbox_device\" \"test1\" {\n  name = \"%[1]s_1\"\n  comments = \"this is also first comment\"\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  serial = \"ABCDEF1\"\n  local_context_data = jsonencode({\"testkey1\"=\"testvalue1\"})\n}\n\nresource \"netbox_device\" \"test2\" {\n  name = \"%[1]s_2_regex\"\n  comments = \"this is also second comment\"\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  serial = \"ABCDEF2\"\n  tags = [netbox_tag.test_b.name, netbox_tag.test_c.name]\n  local_context_data = jsonencode({\"testkey2\"=\"testvalue2\"})\n}\n\nresource \"netbox_device\" \"test3\" {\n  name = \"%[1]s_3_regex\"\n  comments = \"this is also third comment\"\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  serial = \"ABCDEF3\"\n  local_context_data = jsonencode({\"testkey3\"=\"testvalue3\"})\n}\n`, testName)\n}\n\nfunc testAccNetboxDeviceDataSourceFilterName(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_devices\" \"test\" {\n  filter {\n    name  = \"name\"\n    value = \"%[1]s_0\"\n  }\n}`, testName)\n}\n\nconst testAccNetboxDeviceDataSourceFilterTenant = `\ndata \"netbox_devices\" \"test\" {\n  filter {\n    name  = \"tenant_id\"\n    value = netbox_tenant.test.id\n  }\n}`\n\nconst testAccNetBoxDeviceDataSourceFilterTagsAndStatus = `\ndata \"netbox_devices\" \"tag_devices\" {\n  filter {\n    name  = \"tags\"\n    value = netbox_tag.test_a.name\n  }\n  filter {\n\tname  = \"status\"\n    value = \"staged\"\n  }\n}`\n\nconst testAccNetBoxDeviceDataSourceMultipleTagsFilter = `\ndata \"netbox_devices\" \"multiple_filter_devices\" {\n  filter {\n    name  = \"tags\"\n    value = join(\",\", [netbox_tag.test_b.name, netbox_tag.test_c.name])\n  }\n}`\n\nconst testAccNetboxDeviceDataSourceFilterRole = `\ndata \"netbox_devices\" \"test\" {\n  filter {\n    name  = \"role_id\"\n    value = netbox_device_role.test.id\n  }\n}`\n\nfunc testAccNetboxDeviceDataSourceNameRegex(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_devices\" \"test\" {\n  name_regex = \"%[1]s.*_regex\"\n}`, testName)\n}\n\nconst testAccNetboxDeviceDataSourceLimit = `\ndata \"netbox_devices\" \"test\" {\n  limit = 1\n  filter {\n    name  = \"tenant_id\"\n    value = netbox_tenant.test.id\n  }\n}`\n\nfunc TestAccNetboxDevicesDataSource_CustomFields(t *testing.T) {\n\ttestSlug := \"device_ds_customfields\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestField := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\ndata \"netbox_devices\" \"test\" {\n  depends_on = [\n    netbox_device.test,\n    netbox_custom_field.test,\n  ]\n\n  filter {\n    name  = \"name\"\n    value = \"%[2]s\"\n  }\n}\n\nresource \"netbox_custom_field\" \"test\" {\n  name          = \"%[1]s\"\n  type          = \"text\"\n  content_types = [\"dcim.device\"]\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[2]s\"\n  comments = \"thisisacomment\"\n  description = \"thisisadescription\"\n  tenant_id = netbox_tenant.test.id\n  platform_id = netbox_platform.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  tags = [netbox_tag.test_a.name]\n  site_id = netbox_site.test.id\n  cluster_id = netbox_cluster.test.id\n  location_id = netbox_location.test.id\n  status = \"staged\"\n  serial = \"ABCDEF\"\n  custom_fields = {\"${netbox_custom_field.test.name}\" = \"81\"}\n}\n`, testField, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.description\", \"thisisadescription\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.device_type_id\", \"netbox_device_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_devices.test\", \"devices.0.location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.serial\", \"ABCDEF\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.status\", \"staged\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_devices.test\", \"devices.0.custom_fields.\"+testField, \"81\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_interfaces.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxInterfaces() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxInterfaceRead,\n\t\tDescription: `:meta:subcategory:Virtualization:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t\tDescription:      \"The limit of objects to return from the API lookup.\",\n\t\t\t},\n\t\t\t\"name_regex\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringIsValidRegExp,\n\t\t\t},\n\t\t\t\"interfaces\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"enabled\": {\n\t\t\t\t\t\t\tType:     schema.TypeBool,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mac_address\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mode\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mtu\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tag_ids\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tagged_vlans\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"vid\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t// Do as a TypeList due to limitation of TypeMap\n\t\t\t\t\t\t\"untagged_vlan\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"vid\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vm_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxInterfaceRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := virtualization.NewVirtualizationInterfacesListParams()\n\n\t// Get user limit (0 = fetch all)\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"cluster_id\":\n\t\t\t\tparams.ClusterID = &vString\n\t\t\tcase \"mac_address\":\n\t\t\t\tparams.MacAddress = &vString\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"tag\":\n\t\t\t\tparams.Tag = []string{vString} //TODO: switch schema to list?\n\t\t\tcase \"vm_id\":\n\t\t\t\tparams.VirtualMachineID = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination (fetch all when name_regex is used)\n\tpaginationHelper := NewPaginationHelper(FetchAll)\n\tvar allInterfaces []*models.VMInterface\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Virtualization.VirtualizationInterfacesList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch interfaces at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallInterfaces = append(allInterfaces, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allInterfaces)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Apply name_regex filter\n\tvar filteredInterfaces []*models.VMInterface\n\tif nameRegex, ok := d.GetOk(\"name_regex\"); ok {\n\t\tr := regexp.MustCompile(nameRegex.(string))\n\t\tfor _, vmInterface := range allInterfaces {\n\t\t\tif r.MatchString(*vmInterface.Name) {\n\t\t\t\tfilteredInterfaces = append(filteredInterfaces, vmInterface)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfilteredInterfaces = allInterfaces\n\t}\n\n\t// Apply user limit to filtered results\n\tif userLimit > 0 && int64(len(filteredInterfaces)) > userLimit {\n\t\tfilteredInterfaces = filteredInterfaces[:userLimit]\n\t}\n\n\tif len(filteredInterfaces) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredInterfaces {\n\t\tvar mapping = make(map[string]interface{})\n\t\tmapping[\"id\"] = v.ID\n\t\tif v.Description != \"\" {\n\t\t\tmapping[\"description\"] = v.Description\n\t\t}\n\t\tmapping[\"enabled\"] = v.Enabled\n\t\tif v.MacAddress != nil {\n\t\t\tmapping[\"mac_address\"] = *v.MacAddress\n\t\t}\n\t\tif v.Mode != nil {\n\t\t\tmapping[\"mode\"] = map[string]string{\n\t\t\t\t\"label\": *v.Mode.Label,\n\t\t\t\t\"value\": *v.Mode.Value,\n\t\t\t}\n\t\t}\n\t\tif v.Mtu != nil {\n\t\t\tmapping[\"mtu\"] = *v.Mtu\n\t\t}\n\t\tif v.Name != nil {\n\t\t\tmapping[\"name\"] = *v.Name\n\t\t}\n\t\tif v.TaggedVlans != nil {\n\t\t\tmapping[\"tagged_vlans\"] = flattenVlanAttributes(v.TaggedVlans)\n\t\t}\n\t\tif v.Tags != nil {\n\t\t\tvar tags []int64\n\t\t\tfor _, t := range v.Tags {\n\t\t\t\ttags = append(tags, t.ID)\n\t\t\t}\n\t\t\tmapping[\"tag_ids\"] = tags\n\t\t}\n\t\tif v.UntaggedVlan != nil {\n\t\t\tvlanSlice := []*models.NestedVLAN{v.UntaggedVlan}\n\t\t\tmapping[\"untagged_vlan\"] = flattenVlanAttributes(vlanSlice)\n\t\t}\n\n\t\tmapping[\"vm_id\"] = v.VirtualMachine.ID\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"interfaces\", s)\n}\n\nfunc flattenVlanAttributes(vlans []*models.NestedVLAN) []map[string]interface{} {\n\tvar mappedVlans []map[string]interface{}\n\tfor _, vlan := range vlans {\n\t\tv := *vlan\n\t\tmappedVlan := map[string]interface{}{\n\t\t\t\"id\":   v.ID,\n\t\t\t\"vid\":  *v.Vid,\n\t\t\t\"name\": *v.Name,\n\t\t}\n\t\tmappedVlans = append(mappedVlans, mappedVlan)\n\t}\n\treturn mappedVlans\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_interfaces_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxInterfacesDataSource_basic(t *testing.T) {\n\ttestSlug := \"interface_ds_basic\"\n\ttestResource := \"data.netbox_interfaces.test\"\n\ttestName := testAccGetTestName(testSlug)\n\tdependencies := testAccNetboxInterfacesDataSourceDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxInterfacesDataSourceFilterName(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(testResource, \"interfaces.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(testResource, \"interfaces.0.name\", testName+\"_0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(testResource, \"interfaces.0.enabled\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(testResource, \"interfaces.0.vm_id\", \"netbox_virtual_machine.test0\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(testResource, \"interfaces.0.id\", \"netbox_interface.vm0_1\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxInterfacesDataSourceFilterVM,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(testResource, \"interfaces.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(testResource, \"interfaces.0.vm_id\", \"netbox_virtual_machine.test1\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(testResource, \"interfaces.1.vm_id\", \"netbox_virtual_machine.test1\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxInterfacesDataSourceFilterVMWithLimit,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(testResource, \"interfaces.#\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxInterfacesDataSourceNameRegex,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(testResource, \"interfaces.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(testResource, \"interfaces.0.name\", testName+\"_2_regex\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxInterfacesDataSourceDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n\nresource \"netbox_virtual_machine\" \"test0\" {\n  name = \"%[1]s_0\"\n  cluster_id = netbox_cluster.test.id\n}\n\nresource \"netbox_virtual_machine\" \"test1\" {\n  name = \"%[1]s_1\"\n  cluster_id = netbox_cluster.test.id\n}\n\nresource \"netbox_interface\" \"vm0_1\" {\n  name = \"%[1]s_0\"\n  virtual_machine_id = netbox_virtual_machine.test0.id\n}\n\nresource \"netbox_interface\" \"vm1_1\" {\n  name = \"%[1]s_1\"\n  virtual_machine_id = netbox_virtual_machine.test1.id\n}\n\nresource \"netbox_interface\" \"vm1_2\" {\n  name = \"%[1]s_2_regex\"\n  virtual_machine_id = netbox_virtual_machine.test1.id\n}`, testName)\n}\n\nconst testAccNetboxInterfacesDataSourceFilterVM = `\ndata \"netbox_interfaces\" \"test\" {\n  filter {\n    name  = \"vm_id\"\n    value = netbox_virtual_machine.test1.id\n  }\n}`\n\nconst testAccNetboxInterfacesDataSourceFilterVMWithLimit = `\ndata \"netbox_interfaces\" \"test\" {\n  limit = 1\n\n  filter {\n    name  = \"vm_id\"\n    value = netbox_virtual_machine.test1.id\n  }\n}`\n\nfunc testAccNetboxInterfacesDataSourceFilterName(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_interfaces\" \"test\" {\n  filter {\n    name  = \"name\"\n    value = \"%[1]s_0\"\n  }\n}`, testName)\n}\n\nconst testAccNetboxInterfacesDataSourceNameRegex = `\ndata \"netbox_interfaces\" \"test\" {\n  name_regex = \"test.*_regex\"\n}`\n"
  },
  {
    "path": "netbox/data_source_netbox_ip_address.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxIPAddress() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxIPAddressRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.IntAtLeast(1),\n\t\t\t},\n\t\t\t\"ip_address\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"created\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"last_updated\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"custom_fields\": {\n\t\t\t\tType:     schema.TypeMap,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"address_family\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"dns_name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"role\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\n\t\t\t\"tenant\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"tags\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"display\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxIPAddressRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid := d.Get(\"id\").(int)\n\n\tparams := ipam.NewIpamIPAddressesReadParams()\n\tparams.SetID(int64(id))\n\n\tres, err := api.Ipam.IpamIPAddressesRead(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresult := res.GetPayload()\n\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\n\td.Set(\"id\", result.ID)\n\td.Set(\"ip_address\", result.Address)\n\td.Set(\"description\", result.Description)\n\td.Set(\"created\", result.Created.String())\n\td.Set(\"last_updated\", result.LastUpdated.String())\n\td.Set(\"custom_fields\", flattenCustomFields(result.CustomFields))\n\td.Set(\"address_family\", result.Family.Label)\n\td.Set(\"status\", result.Status.Value)\n\td.Set(\"dns_name\", result.DNSName)\n\n\tif result.Role != nil {\n\t\td.Set(\"role\", result.Role.Value)\n\t}\n\n\tvar tenant []map[string]interface{}\n\tif result.Tenant != nil {\n\t\tvar mapping = make(map[string]interface{})\n\t\tmapping[\"id\"] = result.Tenant.ID\n\t\tmapping[\"name\"] = result.Tenant.Name\n\t\tmapping[\"slug\"] = result.Tenant.Slug\n\t\ttenant = append(tenant, mapping)\n\t}\n\td.Set(\"tenant\", tenant)\n\n\tvar tags []map[string]interface{}\n\tfor _, t := range result.Tags {\n\t\tvar tagmapping = make(map[string]interface{})\n\t\ttagmapping[\"name\"] = t.Name\n\t\ttagmapping[\"display\"] = t.Display\n\t\ttagmapping[\"slug\"] = t.Slug\n\t\ttagmapping[\"id\"] = t.ID\n\t\ttags = append(tags, tagmapping)\n\t}\n\td.Set(\"tags\", tags)\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ip_address_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxIpAddressDataSource_basic(t *testing.T) {\n\tipAddress := \"10.0.0.107/24\"\n\tstatus := \"active\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%[1]s\"\n  status = \"%[2]s\"\n}\ndata \"netbox_ip_address\" \"test\" {\n  depends_on = [netbox_ip_address.test]\n  id = netbox_ip_address.test.id\n}`, ipAddress, status),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_address.test\", \"ip_address\", \"netbox_ip_address.test\", \"ip_address\"),\n\t\t\t\t),\n\t\t\t\tExpectNonEmptyPlan: false,\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ip_addresses.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxIPAddresses() *schema.Resource {\n\tcustomFieldsFilterSchema := *customFieldsSchema\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxIPAddressesRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\tcustomFieldsKey: &customFieldsFilterSchema,\n\t\t\t\"ip_addresses\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"created\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"last_updated\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"custom_fields\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"ip_address\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"address_family\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"dns_name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\"tenant\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tags\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"display\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxIPAddressesRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamIPAddressesListParams()\n\tvar opts []ipam.ClientOption\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tvar tags []string\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"dns_name\":\n\t\t\t\tparams.DNSName = &vString\n\t\t\tcase \"interface_id\":\n\t\t\t\tparams.InterfaceID = &vString\n\t\t\tcase \"device_id\":\n\t\t\t\tparams.DeviceID = &vString\n\t\t\tcase \"ip_address\":\n\t\t\t\tparams.Address = &vString\n\t\t\tcase \"vm_interface_id\":\n\t\t\t\tparams.VminterfaceID = &vString\n\t\t\tcase \"role\":\n\t\t\t\tparams.Role = &vString\n\t\t\tcase \"status\":\n\t\t\t\tparams.Status = &vString\n\t\t\tcase \"vrf\":\n\t\t\t\tparams.Vrf = &vString\n\t\t\tcase \"tenant\":\n\t\t\t\tparams.Tenant = &vString\n\t\t\tcase \"parent_prefix\":\n\t\t\t\tparams.Parent = &vString\n\t\t\tcase \"tag\":\n\t\t\t\ttags = append(tags, vString)\n\t\t\t\tparams.Tag = tags\n\t\t\tcase \"description\":\n\t\t\t\tparams.Description = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allIPAddresses []*models.IPAddress\n\n\tif cfm, ok := d.Get(customFieldsKey).(map[string]interface{}); ok {\n\t\topts = append(opts, WithCustomFieldParamsOption(cfm))\n\t}\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Ipam.IpamIPAddressesList(params, nil, opts...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch IP addresses at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallIPAddresses = append(allIPAddresses, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allIPAddresses)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allIPAddresses))\n\tfilteredIPAddresses := allIPAddresses[:trimmedCount]\n\n\tif len(filteredIPAddresses) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredIPAddresses {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = v.ID\n\t\tmapping[\"description\"] = v.Description\n\t\tmapping[\"created\"] = v.Created.String()\n\t\tmapping[\"last_updated\"] = v.LastUpdated.String()\n\t\tmapping[\"custom_fields\"] = flattenCustomFields(v.CustomFields)\n\n\t\tmapping[\"ip_address\"] = v.Address\n\t\tmapping[\"address_family\"] = v.Family.Label\n\t\tmapping[\"status\"] = v.Status.Value\n\t\tmapping[\"dns_name\"] = v.DNSName\n\t\tmapping[\"tenant\"] = flattenTenant(v.Tenant)\n\t\tvar stags []map[string]interface{}\n\t\tfor _, t := range v.Tags {\n\t\t\tvar tagmapping = make(map[string]interface{})\n\t\t\ttagmapping[\"name\"] = t.Name\n\t\t\ttagmapping[\"display\"] = t.Display\n\t\t\ttagmapping[\"slug\"] = t.Slug\n\t\t\ttagmapping[\"id\"] = t.ID\n\t\t\tstags = append(stags, tagmapping)\n\t\t}\n\t\tmapping[\"tags\"] = stags\n\t\tif v.Role != nil {\n\t\t\tmapping[\"role\"] = v.Role.Value\n\t\t}\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"ip_addresses\", s)\n}\n\nfunc flattenTenant(tenant *models.NestedTenant) []map[string]interface{} {\n\tvar s []map[string]interface{}\n\tif tenant != nil {\n\t\tvar mapping = make(map[string]interface{})\n\t\tmapping[\"id\"] = tenant.ID\n\t\tmapping[\"name\"] = tenant.Name\n\t\tmapping[\"slug\"] = tenant.Slug\n\t\ts = append(s, mapping)\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ip_addresses_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxIpAddressesDataSource_basic(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestIP := \"203.0.113.1/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n\tip_address = \"%s\"\n\tvirtual_machine_interface_id = netbox_interface.test.id\n\tstatus = \"active\"\n\ttags = [netbox_tag.test.name]\n\trole = \"anycast\"\n}\ndata \"netbox_ip_addresses\" \"test\" {\n\tdepends_on = [netbox_ip_address.test]\n}`, testIP),\n\t\t\t\t//                              This snippet sometimes returns things from other tests, even if resource.Test is used instead of resource.ParallelTest\n\t\t\t\t//                              This happens especially in CI testing (where test execution is presumably slow)\n\t\t\t\t//                              The check functions are now removed so this does no longer happen\n\t\t\t\t//\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t//\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test\", \"ip_addresses.0.ip_address\", \"netbox_ip_address.test\", \"ip_address\"),\n\t\t\t\t//\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test\", \"ip_addresses.0.role\", \"anycast\"),\n\t\t\t\t//\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test\", \"ip_addresses.0.tags.0.name\", \"netbox_tag.test\", \"name\"),\n\t\t\t\t//\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpAddressesDataSource_filter(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_filter\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestIP0 := \"203.0.113.1/24\"\n\ttestIP1 := \"203.0.113.2/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test_list_0\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\nresource \"netbox_ip_address\" \"test_list_1\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\ndata \"netbox_ip_addresses\" \"test_list\" {\n\tdepends_on = [netbox_ip_address.test_list_0, netbox_ip_address.test_list_1]\n\n\tfilter {\n\t\tname = \"ip_address\"\n\t\tvalue = \"%s\"\n\t}\n}`, testIP0, testIP1, testIP0),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.ip_address\", \"netbox_ip_address.test_list_0\", \"ip_address\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpAddressesDataSource_filter2(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_filter_role\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestIP0 := \"203.0.113.1/24\"\n\ttestIP1 := \"203.0.113.2/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test_list_0\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  role = \"vip\"\n  tags = [netbox_tag.test.name]\n}\nresource \"netbox_ip_address\" \"test_list_1\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  role = \"vrrp\"\n  tags = [netbox_tag.test.name]\n}\ndata \"netbox_ip_addresses\" \"test_list\" {\n\tdepends_on = [netbox_ip_address.test_list_0, netbox_ip_address.test_list_1]\n\n\tfilter {\n\t\tname = \"role\"\n\t\tvalue = \"vip\"\n\t}\n}`, testIP0, testIP1),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.ip_address\", \"netbox_ip_address.test_list_0\", \"ip_address\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpAddressesDataSource_filter_parent_prefix(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_filter_prefix\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestPrefix1 := \"203.0.113.0/24\"\n\ttestIP0 := \"203.0.113.1/24\"\n\ttestIP1 := \"203.0.200.1/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"testv4\" {\n  prefix = \"%s\"\n  status = \"active\"\n}\nresource \"netbox_ip_address\" \"test_list_0\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\nresource \"netbox_ip_address\" \"test_list_1\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\ndata \"netbox_ip_addresses\" \"test_list\" {\n\tdepends_on = [netbox_ip_address.test_list_0, netbox_ip_address.test_list_1]\n\n\tfilter {\n\t\tname = \"parent_prefix\"\n\t\tvalue = \"%s\"\n\t}\n}`, testPrefix1, testIP0, testIP1, testPrefix1),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.ip_address\", \"netbox_ip_address.test_list_0\", \"ip_address\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpAddressesDataSource_multiple(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_multiple\"\n\ttestIP0 := \"203.0.113.1/24\"\n\ttestIP1 := \"203.0.113.2/24\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test_list_0\" {\n\tip_address = \"%s\"\n\tvirtual_machine_interface_id = netbox_interface.test.id\n\tstatus = \"active\"\n\ttags = [netbox_tag.test.name]\n}\nresource \"netbox_ip_address\" \"test_list_1\" {\n\tip_address = \"%s\"\n\tvirtual_machine_interface_id = netbox_interface.test.id\n\tstatus = \"active\"\n\ttags = [netbox_tag.test.name]\n}\n\ndata \"netbox_ip_addresses\" \"test_list\" {\n\tdepends_on = [netbox_ip_address.test_list_0, netbox_ip_address.test_list_1]\n\n\tfilter {\n\t\tname = \"vm_interface_id\"\n\t\tvalue = netbox_interface.test.id\n\t}\n}`, testIP0, testIP1),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.ip_address\", \"netbox_ip_address.test_list_0\", \"ip_address\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.1.ip_address\", \"netbox_ip_address.test_list_1\", \"ip_address\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpAddressesDataSource_flattenTenant(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_flattenTenant\"\n\ttestIP0 := \"203.0.113.10/24\"\n\ttestIP1 := \"203.0.113.20/24\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test_list_0\" {\n\tip_address = \"%s\"\n\tvirtual_machine_interface_id = netbox_interface.test.id\n\tstatus = \"active\"\n\ttags = [netbox_tag.test.name]\n\ttenant_id = netbox_tenant.test.id\n}\nresource \"netbox_ip_address\" \"test_list_1\" {\n\tip_address = \"%s\"\n\tvirtual_machine_interface_id = netbox_interface.test.id\n\tstatus = \"active\"\n\ttags = [netbox_tag.test.name]\n\ttenant_id = netbox_tenant.test.id\n}\n\ndata \"netbox_ip_addresses\" \"test_list\" {\n\tdepends_on = [netbox_ip_address.test_list_0, netbox_ip_address.test_list_1]\n\n\tfilter {\n\t\tname = \"vm_interface_id\"\n\t\tvalue = netbox_interface.test.id\n\t}\n}`, testIP0, testIP1),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.tenant.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.1.tenant.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.tenant.0.name\", \"netbox_tenant.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.1.tenant.0.name\", \"netbox_tenant.test\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxIPAddressesDataSourceDependenciesMany(testName string) string {\n\treturn testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n}`, testName) + fmt.Sprintf(`\nresource \"netbox_interface\" \"test\" {\n  name = \"test\"\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n\nresource \"netbox_ip_address\" \"test\" {\n  count       = 51\n  ip_address  = \"10.11.12.${count.index}/32\"\n  status      = \"active\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  dns_name = \"%s\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxIpAddressessDataSource_many(t *testing.T) {\n\ttestSlug := \"ip_adrs_ds_many\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressesDataSourceDependenciesMany(testName) + fmt.Sprintf(`\ndata \"netbox_ip_addresses\" \"test\" {\n  depends_on = [netbox_ip_address.test]\n\n  filter {\n    name = \"dns_name\"\n    value = \"%s\"\n  }\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test\", \"ip_addresses.#\", \"51\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressesDataSourceDependenciesMany(testName) + `data \"netbox_ip_addresses\" \"test\" {\n  depends_on = [netbox_ip_address.test]\n  limit = 2\n}`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test\", \"ip_addresses.#\", \"2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpAddressesDataSource_filter_tags(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_filter_tags\"\n\ttestTag := \"default-gw\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestIP0 := \"203.0.113.1/24\"\n\ttestIP1 := \"203.0.113.2/24\"\n\ttestIP2 := \"203.0.113.3/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_tag\" \"gw_tag\" {\n  name = \"%s\"\n}\nresource \"netbox_ip_address\" \"test_list_0\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\nresource \"netbox_ip_address\" \"test_list_1\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  tags = [netbox_tag.test.name, netbox_tag.gw_tag.name]\n}\nresource \"netbox_ip_address\" \"test_list_2\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\ndata \"netbox_ip_addresses\" \"test_list\" {\n\tdepends_on = [netbox_ip_address.test_list_0, netbox_ip_address.test_list_1, netbox_ip_address.test_list_2]\n\n\tfilter {\n\t\tname = \"tag\"\n\t\tvalue = \"%s\"\n\t}\n}`, testTag, testIP0, testIP1, testIP2, testTag),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.ip_address\", \"netbox_ip_address.test_list_1\", \"ip_address\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpAddressesDataSource_filter_description(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_filter_description\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestIP0 := \"203.0.113.1/24\"\n\ttestIP1 := \"203.0.113.2/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test_list_0\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  role = \"vip\"\n  description = \"test 1\"\n}\nresource \"netbox_ip_address\" \"test_list_1\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  role = \"vrrp\"\n  description = \"test 2\"\n}\ndata \"netbox_ip_addresses\" \"test_list\" {\n\tdepends_on = [netbox_ip_address.test_list_0, netbox_ip_address.test_list_1]\n\n\tfilter {\n\t\tname = \"description\"\n\t\tvalue = \"test 1\"\n\t}\n}`, testIP0, testIP1),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.ip_address\", \"netbox_ip_address.test_list_0\", \"ip_address\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpAddressesDataSource_filter_customFields(t *testing.T) {\n\ttestSlug := \"ipam_ipaddrs_ds_filter_cf\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestIP0 := \"203.0.113.1/24\"\n\ttestIP1 := \"203.0.113.2/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name   = \"%s\"\n  type   = \"text\"\n  weight = 100\n  content_types = [\"ipam.ipaddress\"]\n}\nresource \"netbox_ip_address\" \"test_list_0\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"match\"\n  }\n}\nresource \"netbox_ip_address\" \"test_list_1\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"skip\"\n  }\n}\ndata \"netbox_ip_addresses\" \"test_list\" {\n\tdepends_on = [netbox_ip_address.test_list_0, netbox_ip_address.test_list_1]\n\n\tcustom_fields = {\n\t\t\"${netbox_custom_field.test.name}\" = \"match\"\n\t}\n}`, testSlug, testIP0, testIP1),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_addresses.test_list\", \"ip_addresses.0.ip_address\", \"netbox_ip_address.test_list_0\", \"ip_address\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_addresses.test_list\", fmt.Sprintf(\"ip_addresses.0.custom_fields.%s\", testSlug), \"match\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ip_range.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxIPRange() *schema.Resource {\n\tfilterAtLeastOneOf := []string{\n\t\t\"contains\",\n\t\t\"family\",\n\t\t\"vrf_id\",\n\t\t\"tenant_id\",\n\t\t\"status\",\n\t\t\"role_id\",\n\t\t\"description\",\n\t\t\"tag\",\n\t}\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxIPRangeRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"start_address\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"end_address\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"contains\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t\tValidateFunc: validation.IsCIDR,\n\t\t\t},\n\t\t\t\"family\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t\tValidateFunc: validation.IntInSlice([]int{4, 6}),\n\t\t\t\tDescription:  \"The IP family of the IP range. One of 4 or 6\",\n\t\t\t},\n\t\t\t\"vrf_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t\tDescription:  \"Description to include in the data source filter.\",\n\t\t\t},\n\t\t\t\"tag\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t\tDescription:  \"Tag to include in the data source filter (must match the tag's slug).\",\n\t\t\t},\n\t\t\t\"tag__n\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDescription: `Tag to exclude from the data source filter (must match the tag's slug).\nRefer to [Netbox's documentation](https://netboxlabs.com/docs/netbox/reference/filtering/#lookup-expressions)\nfor more information on available lookup expressions.`,\n\t\t\t},\n\t\t\t\"tags\": tagsSchemaRead,\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxIPRangeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamIPRangesListParams()\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tif contains, ok := d.Get(\"contains\").(string); ok && contains != \"\" {\n\t\tparams.Contains = &contains\n\t}\n\n\tif family, ok := d.Get(\"family\").(int); ok && family != 0 {\n\t\tfamilyFloat := float64(family)\n\t\tparams.Family = &familyFloat\n\t}\n\n\tif vrfID, ok := d.Get(\"vrf_id\").(int); ok && vrfID != 0 {\n\t\t// Note that vrf_id is a string pointer in the netbox filter, but we use a number in the provider\n\t\tparams.VrfID = strToPtr(strconv.Itoa(vrfID))\n\t}\n\n\tif tenantID, ok := d.Get(\"tenant_id\").(int); ok && tenantID != 0 {\n\t\t// Note that tenant_id is a string pointer in the netbox filter, but we use a number in the provider\n\t\tparams.TenantID = strToPtr(strconv.Itoa(tenantID))\n\t}\n\n\tif status, ok := d.Get(\"status\").(string); ok && status != \"\" {\n\t\tparams.Status = &status\n\t}\n\n\tif roleID, ok := d.Get(\"role_id\").(int); ok && roleID != 0 {\n\t\tparams.RoleID = strToPtr(strconv.Itoa(roleID))\n\t}\n\n\tif description, ok := d.Get(\"description\").(string); ok && description != \"\" {\n\t\tparams.Description = &description\n\t}\n\n\tif tag, ok := d.Get(\"tag\").(string); ok && tag != \"\" {\n\t\tparams.Tag = []string{tag} //TODO: switch schema to list\n\t}\n\tif tagn, ok := d.Get(\"tag__n\").(string); ok && tagn != \"\" {\n\t\tparams.Tagn = &tagn\n\t}\n\n\tres, err := api.Ipam.IpamIPRangesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than IP range returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no IP range found matching filter\")\n\t}\n\n\tresult := res.GetPayload().Results[0]\n\td.Set(\"id\", result.ID)\n\td.Set(\"start_address\", result.StartAddress)\n\td.Set(\"end_address\", result.EndAddress)\n\td.Set(\"status\", result.Status.Value)\n\td.Set(\"description\", result.Description)\n\td.Set(\"family\", int(*result.Family.Value))\n\td.Set(\"tags\", getTagListFromNestedTagList(result.Tags))\n\n\tif result.Role != nil {\n\t\td.Set(\"role_id\", result.Role.ID)\n\t}\n\tif result.Vrf != nil {\n\t\td.Set(\"vrf_id\", result.Vrf.ID)\n\t}\n\tif result.Tenant != nil {\n\t\td.Set(\"tenant_id\", result.Tenant.ID)\n\t}\n\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ip_range_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxIpRangeDataSource_basic(t *testing.T) {\n\ttestv4StartIP := \"10.0.0.101/24\"\n\ttestv4EndIP := \"10.0.0.150/24\"\n\ttestv6StartIP := \"2001:db8:1:1::/112\"\n\ttestv6EndIP := \"2001:db8:1:1::ffff/112\"\n\ttestSlug := \"ip_range_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_vrf\" \"test\" {\n  name = \"%[1]s_vrf\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s_tenant\"\n}\n\nresource \"netbox_ipam_role\" \"test\" {\n  name = \"%[1]s_role\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s_role\"\n}\n\nresource \"netbox_ip_range\" \"testv4\" {\n  start_address = \"%[2]s\"\n  end_address   = \"%[3]s\"\n  vrf_id        = netbox_vrf.test.id\n  tenant_id     = netbox_tenant.test.id\n  role_id       = netbox_ipam_role.test.id\n  description   = \"%[1]s_description_testv4\"\n  status        = \"active\"\n  tags          = [netbox_tag.test.name]\n}\n\nresource \"netbox_ip_range\" \"testv6\" {\n  start_address = \"%[4]s\"\n  end_address   = \"%[5]s\"\n  description   = \"%[1]s_description_testv6\"\n  status        = \"reserved\"\n}\n\ndata \"netbox_ip_range\" \"by_contains\" {\n  depends_on = [netbox_ip_range.testv4]\n  contains   = \"%[2]s\"\n  family     = 4\n}\n\ndata \"netbox_ip_range\" \"by_family\" {\n  depends_on = [netbox_ip_range.testv6]\n  family     = 6\n}\n\ndata \"netbox_ip_range\" \"by_vrf_id\" {\n  depends_on = [netbox_ip_range.testv4]\n  vrf_id     = netbox_vrf.test.id\n  family     = 4\n}\n\ndata \"netbox_ip_range\" \"by_tenant_id\" {\n  depends_on = [netbox_ip_range.testv4]\n  tenant_id  = netbox_tenant.test.id\n  family     = 4\n}\n\ndata \"netbox_ip_range\" \"by_status\" {\n  depends_on = [netbox_ip_range.testv6]\n  status     = \"reserved\"\n}\n\ndata \"netbox_ip_range\" \"by_role_id\" {\n  depends_on = [netbox_ip_range.testv4]\n  role_id    = netbox_ipam_role.test.id\n  family     = 4\n}\n\ndata \"netbox_ip_range\" \"by_tag\" {\n  depends_on = [netbox_ip_range.testv4]\n  tag = netbox_tag.test.name\n}\n\ndata \"netbox_ip_range\" \"by_description\" {\n  depends_on  = [netbox_ip_range.testv4]\n  description = \"%[1]s_description_testv4\"\n}`, testName, testv4StartIP, testv4EndIP, testv6StartIP, testv6EndIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_range.by_contains\", \"id\", \"netbox_ip_range.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_range.by_family\", \"id\", \"netbox_ip_range.testv6\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_range.by_vrf_id\", \"id\", \"netbox_ip_range.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_range.by_tenant_id\", \"id\", \"netbox_ip_range.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_range.by_status\", \"id\", \"netbox_ip_range.testv6\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_range.by_role_id\", \"id\", \"netbox_ip_range.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_range.by_description\", \"id\", \"netbox_ip_range.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_range.by_tag\", \"id\", \"netbox_ip_range.testv4\", \"id\"),\n\t\t\t\t),\n\t\t\t\tExpectNonEmptyPlan: false,\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ip_ranges.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxIPRanges() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxIPRangesRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"ip_ranges\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"created\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"last_updated\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"custom_fields\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"start_address\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"end_address\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"address_family\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\"tenant\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tags\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"display\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxIPRangesRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamIPRangesListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tvar tags []string\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"contains\":\n\t\t\t\tparams.Contains = &vString\n\t\t\tcase \"start_address\":\n\t\t\t\tparams.StartAddress = &vString\n\t\t\tcase \"end_address\":\n\t\t\t\tparams.EndAddress = &vString\n\t\t\tcase \"role\":\n\t\t\t\tparams.Role = &vString\n\t\t\tcase \"status\":\n\t\t\t\tparams.Status = &vString\n\t\t\tcase \"vrf\":\n\t\t\t\tparams.Vrf = &vString\n\t\t\tcase \"tenant\":\n\t\t\t\tparams.Tenant = &vString\n\t\t\tcase \"tag\":\n\t\t\t\ttags = append(tags, vString)\n\t\t\t\tparams.Tag = tags\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allIPRanges []*models.IPRange\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Ipam.IpamIPRangesList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch IP ranges at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallIPRanges = append(allIPRanges, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allIPRanges)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allIPRanges))\n\tfilteredIPRanges := allIPRanges[:trimmedCount]\n\n\tif len(filteredIPRanges) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredIPRanges {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = v.ID\n\t\tmapping[\"description\"] = v.Description\n\t\tmapping[\"created\"] = v.Created.String()\n\t\tmapping[\"last_updated\"] = v.LastUpdated.String()\n\t\tmapping[\"custom_fields\"] = flattenCustomFields(v.CustomFields)\n\n\t\tmapping[\"start_address\"] = v.StartAddress\n\t\tmapping[\"end_address\"] = v.EndAddress\n\t\tmapping[\"address_family\"] = v.Family.Label\n\t\tmapping[\"status\"] = v.Status.Value\n\t\tmapping[\"tenant\"] = flattenTenant(v.Tenant)\n\t\tif v.Vrf != nil {\n\t\t\tmapping[\"vrf_id\"] = v.Vrf.ID\n\t\t}\n\t\tif v.Role != nil {\n\t\t\tmapping[\"role_id\"] = v.Role.ID\n\t\t}\n\t\tmapping[\"description\"] = v.Description\n\t\tvar stags []map[string]interface{}\n\t\tfor _, t := range v.Tags {\n\t\t\tvar tagmapping = make(map[string]interface{})\n\t\t\ttagmapping[\"name\"] = t.Name\n\t\t\ttagmapping[\"display\"] = t.Display\n\t\t\ttagmapping[\"slug\"] = t.Slug\n\t\t\ttagmapping[\"id\"] = t.ID\n\t\t\tstags = append(stags, tagmapping)\n\t\t}\n\t\tmapping[\"tags\"] = stags\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"ip_ranges\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ip_ranges_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxIpRangesDataSource_basic(t *testing.T) {\n\ttestStartIP := \"11.0.0.101/24\"\n\ttestEndIP := \"11.0.0.150/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test\" {\n  start_address = \"%[1]s\"\n  end_address = \"%[2]s\"\n}\ndata \"netbox_ip_ranges\" \"test\" {\n  depends_on = [netbox_ip_range.test]\n}`, testStartIP, testEndIP),\n\t\t\t\t// This snippet sometimes returns things from other tests, yielding a different number than the expected 1\n\t\t\t\t// The check functions are now removed so this does no longer happen\n\t\t\t\t// Check: resource.ComposeTestCheckFunc(\n\t\t\t\t// \tresource.TestCheckResourceAttr(\"data.netbox_ip_ranges.test\", \"ip_ranges.#\", \"1\"),\n\t\t\t\t// ),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpRangesDataSource_filter(t *testing.T) {\n\ttestSlug := \"ipam_ipranges_ds_filter\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestStartIP0 := \"12.0.0.101/24\"\n\ttestEndIP0 := \"12.0.0.150/24\"\n\ttestStartIP1 := \"13.0.0.101/24\"\n\ttestEndIP1 := \"13.0.0.150/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\n\nresource \"netbox_ip_range\" \"test_range_0\" {\n  start_address = \"%[1]s\"\n  end_address = \"%[2]s\"\n}\n  resource \"netbox_ip_range\" \"test_range_1\" {\n  start_address = \"%[3]s\"\n  end_address = \"%[4]s\"\n}\ndata \"netbox_ip_ranges\" \"test_list\" {\n\tdepends_on = [netbox_ip_range.test_range_0, netbox_ip_range.test_range_1]\n\n\tfilter {\n\t\tname = \"start_address\"\n\t\tvalue = \"%[1]s\"\n\t}\n}`, testStartIP0, testEndIP0, testStartIP1, testEndIP1),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_ip_ranges.test_list\", \"ip_ranges.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ip_ranges.test_list\", \"ip_ranges.0.start_address\", \"netbox_ip_range.test_range_0\", \"start_address\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ipam_role.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxIPAMRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxIPAMRoleRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"weight\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxIPAMRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tparams := ipam.NewIpamRolesListParams()\n\tparams.Name = &name\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Ipam.IpamRolesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one ipam role returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no ipam role found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"name\", result.Name)\n\tif result.Weight != nil {\n\t\td.Set(\"weight\", result.Weight)\n\t}\n\tif result.Description != \"\" {\n\t\td.Set(\"description\", result.Description)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_ipam_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxIPAMRoleDataSource_basic(t *testing.T) {\n\ttestSlug := \"ipamrole_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ipam_role\" \"test\" {\n\tname = \"%[1]s\"\n}\ndata \"netbox_ipam_role\" \"test\" {\n\tdepends_on = [netbox_ipam_role.test]\n\tname = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_ipam_role.test\", \"id\", \"netbox_ipam_role.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_location.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxLocation() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxLocationRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"id\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tComputed: true,\n\t\t\t},\n\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxLocationRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := dcim.NewDcimLocationsListParams()\n\n\tparams.Limit = int64ToPtr(2)\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.SetName(&name)\n\t}\n\tif slug, ok := d.Get(\"slug\").(string); ok && slug != \"\" {\n\t\tparams.SetSlug(&slug)\n\t}\n\tif id, ok := d.Get(\"id\").(string); ok && id != \"0\" {\n\t\tparams.SetID(&id)\n\t}\n\tif site, ok := d.Get(\"site_id\").(int); ok && site != 0 {\n\t\tsiteID := fmt.Sprintf(\"%v\", site)\n\t\tparams.SetSiteID(&siteID)\n\t}\n\tif parent, ok := d.Get(\"parent_id\").(int); ok && parent != 0 {\n\t\tparentID := fmt.Sprintf(\"%v\", parent)\n\t\tparams.SetParentID(&parentID)\n\t}\n\tres, err := api.Dcim.DcimLocationsList(params, nil)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one location returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no location found matching filter\")\n\t}\n\n\tlocation := res.GetPayload().Results[0]\n\n\td.SetId(strconv.FormatInt(location.ID, 10))\n\td.Set(\"description\", location.Description)\n\td.Set(\"name\", location.Name)\n\td.Set(\"site_id\", location.Site.ID)\n\td.Set(\"slug\", location.Slug)\n\n\tif location.Parent != nil {\n\t\td.Set(\"parent_id\", location.Parent.ID)\n\t}\n\tif location.Status != nil {\n\t\td.Set(\"status\", location.Status.Value)\n\t}\n\tif location.Tenant != nil {\n\t\td.Set(\"tenant_id\", location.Tenant.ID)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_location_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxLocationDataSource_basic(t *testing.T) {\n\ttestSlug := \"location_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestNameSub := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name        = \"%[1]s\"\n  description = \"my-description\"\n  site_id     = netbox_site.test.id\n  tenant_id   = netbox_tenant.test.id\n}\n\nresource \"netbox_location\" \"test_sub\" {\n  name        = \"%[2]s\"\n  description = \"my-description\"\n  site_id     = netbox_site.test.id\n  tenant_id   = netbox_tenant.test.id\n  parent_id   = netbox_location.test.id\n}\n\ndata \"netbox_location\" \"by_name\" {\n  name = netbox_location.test.name\n}\n\ndata \"netbox_location\" \"by_name_and_site\" {\n  name    = netbox_location.test.name\n  site_id = netbox_site.test.id\n}\n\ndata \"netbox_location\" \"sub_by_name\" {\n  name = netbox_location.test_sub.name\n}\n\ndata \"netbox_location\" \"by_id\" {\n  id = netbox_location.test.id\n}\n\ndata \"netbox_location\" \"by_slug\" {\n  slug = netbox_location.test.slug\n}`, testName, testNameSub),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.by_name\", \"id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.by_id\", \"id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.by_slug\", \"id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_location.by_name\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.by_name\", \"id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.by_name\", \"description\", \"netbox_location.test\", \"description\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.by_name\", \"site_id\", \"netbox_location.test\", \"site_id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.by_name_and_site\", \"site_id\", \"netbox_location.test\", \"site_id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.by_name\", \"tenant_id\", \"netbox_location.test\", \"tenant_id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_location.sub_by_name\", \"parent_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_locations.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxLocations() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxLocationsRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:        schema.TypeSet,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"A list of filter to apply to the API query when requesting locations.\",\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:        schema.TypeString,\n\t\t\t\t\t\t\tRequired:    true,\n\t\t\t\t\t\t\tDescription: \"The name of the field to filter on. Supported fields are: .\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:        schema.TypeString,\n\t\t\t\t\t\t\tRequired:    true,\n\t\t\t\t\t\t\tDescription: \"The value to pass to the specified filter.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"tags\": {\n\t\t\t\tType: schema.TypeSet,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"A list of tags to filter on.\",\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t\tDescription:      \"The limit of objects to return from the API lookup.\",\n\t\t\t},\n\t\t\t\"locations\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"facility\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tenant_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"parent_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxLocationsRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := dcim.NewDcimLocationsListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"slug\":\n\t\t\t\tparams.Slug = &vString\n\t\t\tcase \"site\":\n\t\t\t\tparams.Site = &vString\n\t\t\tcase \"site_id\":\n\t\t\t\tparams.SiteID = &vString\n\t\t\tcase \"parent_id\":\n\t\t\t\tparams.ParentID = &vString\n\t\t\tcase \"tenant\":\n\t\t\t\tparams.Tenant = &vString\n\t\t\tcase \"tenant_id\":\n\t\t\t\tparams.TenantID = &vString\n\t\t\tcase \"status\":\n\t\t\t\tparams.Status = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\tif tags, ok := d.GetOk(\"tags\"); ok {\n\t\ttagSet := tags.(*schema.Set)\n\t\tfor _, tag := range tagSet.List() {\n\t\t\ttagV := tag.(string)\n\t\t\tparams.Tag = append(params.Tag, tagV)\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allLocations []*models.Location\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Dcim.DcimLocationsList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch locations at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallLocations = append(allLocations, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allLocations)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allLocations))\n\tfilteredLocations := allLocations[:trimmedCount]\n\n\tvar s []map[string]any\n\tfor _, v := range filteredLocations {\n\t\tvar mapping = make(map[string]any)\n\n\t\tmapping[\"id\"] = strconv.FormatInt(v.ID, 10)\n\t\tmapping[\"name\"] = v.Name\n\t\tmapping[\"slug\"] = v.Slug\n\t\tmapping[\"site_id\"] = v.Site.ID\n\t\tmapping[\"description\"] = v.Description\n\t\tmapping[\"facility\"] = v.Facility\n\n\t\tif v.Parent != nil {\n\t\t\tmapping[\"parent_id\"] = v.Parent.ID\n\t\t}\n\n\t\tif v.Status != nil {\n\t\t\tmapping[\"status\"] = v.Status.Value\n\t\t}\n\n\t\tif v.Tenant != nil {\n\t\t\tmapping[\"tenant_id\"] = v.Tenant.ID\n\t\t}\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"locations\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_locations_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxLocationsDataSource_basic(t *testing.T) {\n\ttestSlug := \"location_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name        = \"%[1]s\"\n  description = \"my-description\"\n  facility    = \"Building B\"\n  site_id     = netbox_site.test.id\n  tenant_id   = netbox_tenant.test.id\n  tags        = [netbox_tag.test.slug]\n}\n\ndata \"netbox_locations\" \"by_name\" {\n  filter {\n    name  = \"name\"\n    value = netbox_location.test.name\n  }\n}\n\ndata \"netbox_locations\" \"no_match\" {\n  filter {\n    name  = \"name\"\n    value = \"non-existent\"\n  }\n}\n\ndata \"netbox_locations\" \"by_site_slug\" {\n  filter {\n    name  = \"site\"\n    value = netbox_site.test.slug\n  }\n  depends_on = [netbox_location.test]\n}\n\ndata \"netbox_locations\" \"by_site_id\" {\n  filter {\n    name  = \"site_id\"\n    value = netbox_site.test.id\n  }\n  depends_on = [netbox_location.test]\n}\n\ndata \"netbox_locations\" \"by_tenant_slug\" {\n  filter {\n    name  = \"tenant\"\n    value = netbox_tenant.test.slug\n  }\n  depends_on = [netbox_location.test]\n}\n\ndata \"netbox_locations\" \"by_tenant_id\" {\n  filter {\n    name  = \"tenant_id\"\n    value = netbox_tenant.test.id\n  }\n  depends_on = [netbox_location.test]\n}\n\ndata \"netbox_locations\" \"by_tags\" {\n  tags       = [netbox_tag.test.slug]\n  depends_on = [netbox_location.test]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_name\", \"locations.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_name\", \"locations.0.name\", \"netbox_location.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_name\", \"locations.0.site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_name\", \"locations.0.tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_name\", \"locations.0.parent_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_name\", \"locations.0.description\", \"my-description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_name\", \"locations.0.facility\", \"Building B\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.no_match\", \"locations.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_site_slug\", \"locations.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_site_slug\", \"locations.0.name\", \"netbox_location.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_site_id\", \"locations.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_site_id\", \"locations.0.name\", \"netbox_location.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_tenant_slug\", \"locations.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_tenant_slug\", \"locations.0.name\", \"netbox_location.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_tenant_id\", \"locations.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_tenant_id\", \"locations.0.name\", \"netbox_location.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_tags\", \"locations.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_tags\", \"locations.0.name\", \"netbox_location.test\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxLocationsDataSource_multiple(t *testing.T) {\n\ttestSlug := \"location_ds_multiple\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"test1\" {\n  name = \"%[1]s_1\"\n}\n\nresource \"netbox_tag\" \"test2\" {\n  name = \"%[1]s_2\"\n}\n\nresource \"netbox_location\" \"test1\" {\n  name        = \"%[1]s_1\"\n  site_id     = netbox_site.test.id\n  tenant_id   = netbox_tenant.test.id\n  tags        = [netbox_tag.test1.slug]\n}\n\nresource \"netbox_location\" \"test2\" {\n  name        = \"%[1]s_2\"\n  site_id     = netbox_site.test.id\n  tenant_id   = netbox_tenant.test.id\n  tags        = [netbox_tag.test2.slug]\n}\n\ndata \"netbox_locations\" \"by_site\" {\n  filter {\n    name  = \"site\"\n    value = netbox_site.test.name\n  }\n  depends_on = [netbox_location.test1, netbox_location.test2]\n}\n\ndata \"netbox_locations\" \"by_tag\" {\n  tags = [netbox_tag.test1.slug]\n  depends_on = [netbox_location.test1, netbox_location.test2]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_site\", \"locations.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_tag\", \"locations.#\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxLocationsDataSource_sublocations(t *testing.T) {\n\ttestSlug := \"sublocations_ds_multiple\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_location\" \"parent\" {\n  name      = \"%[1]s_p\"\n  site_id   = netbox_site.test.id\n  tenant_id = netbox_tenant.test.id\n}\n\nresource \"netbox_location\" \"test1\" {\n  name      = \"%[1]s_1\"\n  parent_id = netbox_location.parent.id\n  site_id   = netbox_site.test.id\n  tenant_id = netbox_tenant.test.id\n}\n\nresource \"netbox_location\" \"test2\" {\n  name      = \"%[1]s_2\"\n  parent_id = netbox_location.parent.id\n  site_id   = netbox_site.test.id\n  tenant_id = netbox_tenant.test.id\n}\n\ndata \"netbox_locations\" \"by_parent\" {\n  filter {\n    name  = \"parent_id\"\n    value = netbox_location.parent.id\n  }\n  depends_on = [netbox_location.test1, netbox_location.test2]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_locations.by_parent\", \"locations.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_parent\", \"locations.0.parent_id\", \"netbox_location.parent\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_locations.by_parent\", \"locations.1.parent_id\", \"netbox_location.parent\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_platform.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxPlatform() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxPlatformRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"manufacturer_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxPlatformRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := dcim.NewDcimPlatformsListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Dcim.DcimPlatformsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one platform returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no platform found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\tif result.Manufacturer != nil {\n\t\td.Set(\"manufacturer_id\", result.Manufacturer.ID)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_platform_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxPlatformDataSource_basic(t *testing.T) {\n\ttestSlug := \"pltf_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n}\ndata \"netbox_platform\" \"test\" {\n  depends_on = [netbox_platform.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_platform.test\", \"id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPlatformDataSource_manufacturer(t *testing.T) {\n\ttestSlug := \"pltf_ds_manufacturer\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\ndata \"netbox_platform\" \"test\" {\n  depends_on = [netbox_platform.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_platform.test\", \"id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_platform.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_prefix.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxPrefix() *schema.Resource {\n\tfilterAtLeastOneOf := []string{\n\t\t\"description\",\n\t\t\"family\",\n\t\t\"prefix\",\n\t\t\"vlan_vid\",\n\t\t\"vrf_id\",\n\t\t\"vlan_id\",\n\t\t\"tenant_id\",\n\t\t\"site_id\",\n\t\t\"role_id\",\n\t\t\"cidr\",\n\t\t\"custom_fields\",\n\t\t\"tag\",\n\t\t\"status\",\n\t}\n\tcustomFieldsFilterSchema := *customFieldsSchema\n\tcustomFieldsFilterSchema.AtLeastOneOf = filterAtLeastOneOf\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxPrefixRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"cidr\": {\n\t\t\t\tType:          schema.TypeString,\n\t\t\t\tOptional:      true,\n\t\t\t\tDeprecated:    \"The `cidr` parameter is deprecated in favor of the canonical `prefix` attribute.\",\n\t\t\t\tConflictsWith: []string{\"prefix\"},\n\t\t\t\tValidateFunc:  validation.IsCIDR,\n\t\t\t\tAtLeastOneOf:  filterAtLeastOneOf,\n\t\t\t},\n\t\t\tcustomFieldsKey: &customFieldsFilterSchema,\n\t\t\t\"description\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t\tDescription:  \"Description to include in the data source filter.\",\n\t\t\t},\n\t\t\t\"family\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t\tValidateFunc: validation.IntInSlice([]int{4, 6}),\n\t\t\t\tDescription:  \"The IP family of the prefix. One of 4 or 6\",\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"prefix\": {\n\t\t\t\tType:          schema.TypeString,\n\t\t\t\tOptional:      true,\n\t\t\t\tValidateFunc:  validation.IsCIDR,\n\t\t\t\tConflictsWith: []string{\"cidr\"},\n\t\t\t\tAtLeastOneOf:  filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"vlan_vid\": {\n\t\t\t\tType:         schema.TypeFloat,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t\tValidateFunc: validation.FloatBetween(1, 4094),\n\t\t\t},\n\t\t\t\"vrf_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"vlan_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"site_group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"region_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"tag\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t\tDescription:  \"Tag to include in the data source filter (must match the tag's slug).\",\n\t\t\t},\n\t\t\t\"tag__n\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDescription: `Tag to exclude from the data source filter (must match the tag's slug).\nRefer to [Netbox's documentation](https://demo.netbox.dev/static/docs/rest-api/filtering/#lookup-expressions)\nfor more information on available lookup expressions.`,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: filterAtLeastOneOf,\n\t\t\t},\n\t\t\t\"tags\": tagsSchemaRead,\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxPrefixRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamPrefixesListParams()\n\tvar opts []ipam.ClientOption\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\t// note: cidr is deprecated in favor of prefix\n\tif cidr, ok := d.Get(\"cidr\").(string); ok && cidr != \"\" {\n\t\tparams.Prefix = &cidr\n\t}\n\n\tif description, ok := d.Get(\"description\").(string); ok && description != \"\" {\n\t\tparams.Description = &description\n\t}\n\n\tif family, ok := d.Get(\"family\").(int); ok && family != 0 {\n\t\tfamilyFloat := float64(family)\n\t\tparams.Family = &familyFloat\n\t}\n\n\tif roleID, ok := d.Get(\"role_id\").(int); ok && roleID != 0 {\n\t\tparams.RoleID = strToPtr(strconv.Itoa(roleID))\n\t}\n\n\tif prefix, ok := d.Get(\"prefix\").(string); ok && prefix != \"\" {\n\t\tparams.Prefix = &prefix\n\t}\n\n\tif vrfID, ok := d.Get(\"vrf_id\").(int); ok && vrfID != 0 {\n\t\t// Note that vrf_id is a string pointer in the netbox filter, but we use a number in the provider\n\t\tparams.VrfID = strToPtr(strconv.Itoa(vrfID))\n\t}\n\n\tif vlanID, ok := d.Get(\"vlan_id\").(int); ok && vlanID != 0 {\n\t\t// Note that vlan_id is a string pointer in the netbox filter, but we use a number in the provider\n\t\tparams.VlanID = strToPtr(strconv.Itoa(vlanID))\n\t}\n\n\tif vlanVid, ok := d.Get(\"vlan_vid\").(float64); ok && vlanVid != 0 {\n\t\tparams.VlanVid = &vlanVid\n\t}\n\n\tif tenantID, ok := d.Get(\"tenant_id\").(int); ok && tenantID != 0 {\n\t\t// Note that tenant_id is a string pointer in the netbox filter, but we use a number in the provider\n\t\tparams.TenantID = strToPtr(strconv.Itoa(tenantID))\n\t}\n\n\tif siteID, ok := d.Get(\"site_id\").(int); ok && siteID != 0 {\n\t\t// Note that site_id is a string pointer in the netbox filter, but we use a number in the provider\n\t\tparams.SiteID = strToPtr(strconv.Itoa(siteID))\n\t}\n\n\tif tag, ok := d.Get(\"tag\").(string); ok && tag != \"\" {\n\t\tparams.Tag = []string{tag} //TODO: switch schema to list\n\t}\n\tif tagn, ok := d.Get(\"tag__n\").(string); ok && tagn != \"\" {\n\t\tparams.Tagn = &tagn\n\t}\n\n\tif status, ok := d.Get(\"status\").(string); ok && status != \"\" {\n\t\tparams.Status = &status\n\t}\n\n\tif cfm, ok := d.Get(customFieldsKey).(map[string]interface{}); ok {\n\t\topts = append(opts, WithCustomFieldParamsOption(cfm))\n\t}\n\n\tres, err := api.Ipam.IpamPrefixesList(params, nil, opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than prefix returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no prefix found matching filter\")\n\t}\n\n\tresult := res.GetPayload().Results[0]\n\td.Set(\"id\", result.ID)\n\td.Set(\"cidr\", result.Prefix)\n\td.Set(\"prefix\", result.Prefix)\n\td.Set(\"status\", result.Status.Value)\n\td.Set(\"description\", result.Description)\n\td.Set(\"family\", int(*result.Family.Value))\n\td.Set(\"tags\", getTagListFromNestedTagList(result.Tags))\n\n\tcf := getCustomFields(result.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tif result.Role != nil {\n\t\td.Set(\"role_id\", result.Role.ID)\n\t}\n\tif result.Vrf != nil {\n\t\td.Set(\"vrf_id\", result.Vrf.ID)\n\t}\n\tif result.Vlan != nil {\n\t\td.Set(\"vlan_vid\", result.Vlan.Vid)\n\t\td.Set(\"vlan_id\", result.Vlan.ID)\n\t}\n\tif result.Tenant != nil {\n\t\td.Set(\"tenant_id\", result.Tenant.ID)\n\t}\n\n\td.Set(\"site_id\", nil)\n\td.Set(\"site_group_id\", nil)\n\td.Set(\"location_id\", nil)\n\td.Set(\"region_id\", nil)\n\n\tif result.ScopeType != nil && result.ScopeID != nil {\n\t\tscopeID := result.ScopeID\n\t\tswitch scopeType := result.ScopeType; *scopeType {\n\t\tcase \"dcim.site\":\n\t\t\td.Set(\"site_id\", scopeID)\n\t\tcase \"dcim.sitegroup\":\n\t\t\td.Set(\"site_group_id\", scopeID)\n\t\tcase \"dcim.location\":\n\t\t\td.Set(\"location_id\", scopeID)\n\t\tcase \"dcim.region\":\n\t\t\td.Set(\"region_id\", scopeID)\n\t\t}\n\t}\n\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_prefix_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxPrefixDataSource_basic(t *testing.T) {\n\ttestv4Prefix := \"10.0.0.0/24\"\n\ttestv6Prefix := \"2000::/64\"\n\ttestSlug := \"prefix_ds_basic\"\n\ttestVlanVid := 4090\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_vrf\" \"test\" {\n  name = \"%[1]s_vrf\"\n}\n\nresource \"netbox_vlan\" \"test\" {\n  name = \"%[1]s_vlan_test_id\"\n  vid  = %[4]d\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s_tenant\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s_site\"\n}\n\nresource \"netbox_ipam_role\" \"test\" {\n  name = \"%[1]s_role\"\n}\n\nresource \"netbox_prefix\" \"testv4\" {\n  prefix      = \"%[2]s\"\n  status      = \"active\"\n  vrf_id      = netbox_vrf.test.id\n  vlan_id     = netbox_vlan.test.id\n  tenant_id   = netbox_tenant.test.id\n  site_id    = netbox_site.test.id\n  role_id     = netbox_ipam_role.test.id\n  description = \"%[1]s_description_test_idv4\"\n}\n\nresource \"netbox_prefix\" \"testv6\" {\n  prefix      = \"%[3]s\"\n  status      = \"container\"\n  vrf_id      = netbox_vrf.test.id\n  vlan_id     = netbox_vlan.test.id\n  tenant_id   = netbox_tenant.test.id\n  site_id    = netbox_site.test.id\n  description = \"%[1]s_description_test_idv6\"\n}\n\ndata \"netbox_prefix\" \"by_description\" {\n  description = netbox_prefix.testv4.description\n}\n\ndata \"netbox_prefix\" \"by_cidr\" {\n  depends_on = [netbox_prefix.testv4]\n  cidr       = \"%[2]s\"\n}\n\ndata \"netbox_prefix\" \"by_vrf_id\" {\n  depends_on = [netbox_prefix.testv4]\n  vrf_id     = netbox_vrf.test.id\n  family     = 4\n}\n\ndata \"netbox_prefix\" \"by_vlan_id\" {\n  depends_on = [netbox_prefix.testv4]\n  vlan_id    = netbox_vlan.test.id\n  family     = 4\n}\n\ndata \"netbox_prefix\" \"by_vlan_vid\" {\n  depends_on = [netbox_prefix.testv4]\n  vlan_vid   = %[4]d\n  family     = 4\n}\n\ndata \"netbox_prefix\" \"by_prefix\" {\n  depends_on = [netbox_prefix.testv4]\n  prefix     = \"%[2]s\"\n}\n\ndata \"netbox_prefix\" \"by_tenant_id\" {\n  depends_on = [netbox_prefix.testv4]\n  tenant_id  = netbox_tenant.test.id\n  family     = 4\n}\n\ndata \"netbox_prefix\" \"by_site_id\" {\n  depends_on = [netbox_prefix.testv4]\n  site_id    = netbox_site.test.id\n  family     = 4\n}\n\ndata \"netbox_prefix\" \"by_role_id\" {\n  depends_on = [netbox_prefix.testv4]\n  role_id    = netbox_ipam_role.test.id\n}\n\ndata \"netbox_prefix\" \"by_status\" {\n  depends_on = [netbox_prefix.testv4]\n  status     = \"active\"\n}\n\ndata \"netbox_prefix\" \"by_family\" {\n  depends_on = [netbox_prefix.testv6]\n\tfamily   = 6\n}`, testName, testv4Prefix, testv6Prefix, testVlanVid),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_prefix\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_description\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_cidr\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_vrf_id\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_vlan_id\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_vlan_vid\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_tenant_id\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_site_id\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_role_id\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_status\", \"id\", \"netbox_prefix.testv4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_family\", \"id\", \"netbox_prefix.testv6\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPrefixDataSource_customFields(t *testing.T) {\n\ttestSlug := \"prefix_customfields\"\n\ttestPrefix := \"10.0.0.0/24\"\n\ttestField := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name = \"%[1]s\"\n  type = \"text\"\n  content_types = [\"ipam.prefix\"]\n  weight        = 100\n}\n\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%[2]s\"\n  status = \"active\"\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"test value\"\n  }\n}\n\ndata \"netbox_prefix\" \"test_output\" {\n  depends_on = [netbox_prefix.test]\n  prefix = \"%[2]s\"\n}\n\ndata \"netbox_prefix\" \"by_custom_fields\" {\n  depends_on = [netbox_prefix.test]\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"test value\"\n  }\n}\n`, testField, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefix.test_output\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefix.test_output\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefix.test_output\", \"custom_fields.\"+testField, \"test value\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefix.by_custom_fields\", \"id\", \"netbox_prefix.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_prefixes.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxPrefixes() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxPrefixesRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:        schema.TypeSet,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"A list of filters to apply to the API query when requesting prefixes.\",\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:        schema.TypeString,\n\t\t\t\t\t\t\tRequired:    true,\n\t\t\t\t\t\t\tDescription: \"The name of the field to filter on. Supported fields are: `prefix`, `contains`, `vlan_vid`, `vrf_id`, `vlan_id`, `status`, `tenant_id`, `site_id`, `description` & `tag`.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:        schema.TypeString,\n\t\t\t\t\t\t\tRequired:    true,\n\t\t\t\t\t\t\tDescription: \"The value to pass to the specified filter.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t\tDescription:      \"The limit of objects to return from the API lookup.\",\n\t\t\t},\n\t\t\t\"prefixes\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"prefix\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tenant_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site_group_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"location_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"region_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vlan_vid\": {\n\t\t\t\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vrf_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vlan_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tags\": tagsSchemaRead,\n\t\t\t\t\t\tcustomFieldsKey: {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxPrefixesRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamPrefixesListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"prefix\":\n\t\t\t\tparams.Prefix = &vString\n\t\t\tcase \"vlan_vid\":\n\t\t\t\tfloat, err := strconv.ParseFloat(vString, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tparams.VlanVid = &float\n\t\t\tcase \"contains\":\n\t\t\t\tparams.Contains = &vString\n\t\t\tcase \"vrf_id\":\n\t\t\t\tparams.VrfID = &vString\n\t\t\tcase \"vlan_id\":\n\t\t\t\tparams.VlanID = &vString\n\t\t\tcase \"status\":\n\t\t\t\tparams.Status = &vString\n\t\t\tcase \"tenant_id\":\n\t\t\t\tparams.TenantID = &vString\n\t\t\tcase \"site_id\":\n\t\t\t\tparams.SiteID = &vString\n\t\t\tcase \"description\":\n\t\t\t\tparams.Description = &vString\n\t\t\tcase \"tag\":\n\t\t\t\tparams.Tag = []string{vString}\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allPrefixes []*models.Prefix\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Ipam.IpamPrefixesList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch prefixes at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallPrefixes = append(allPrefixes, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allPrefixes)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allPrefixes))\n\tfilteredPrefixes := allPrefixes[:trimmedCount]\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredPrefixes {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = v.ID\n\t\tmapping[\"prefix\"] = v.Prefix\n\t\tmapping[\"description\"] = v.Description\n\t\tif v.Vlan != nil {\n\t\t\tmapping[\"vlan_vid\"] = v.Vlan.Vid\n\t\t\tmapping[\"vlan_id\"] = v.Vlan.ID\n\t\t}\n\t\tif v.Vrf != nil {\n\t\t\tmapping[\"vrf_id\"] = v.Vrf.ID\n\t\t}\n\t\tif v.Tenant != nil {\n\t\t\tmapping[\"tenant_id\"] = v.Tenant.ID\n\t\t}\n\t\tif v.ScopeType != nil && v.ScopeID != nil {\n\t\t\tscopeID := v.ScopeID\n\t\t\tswitch scopeType := v.ScopeType; *scopeType {\n\t\t\tcase \"dcim.site\":\n\t\t\t\tmapping[\"site_id\"] = scopeID\n\t\t\tcase \"dcim.sitegroup\":\n\t\t\t\tmapping[\"site_group_id\"] = scopeID\n\t\t\tcase \"dcim.location\":\n\t\t\t\tmapping[\"location_id\"] = scopeID\n\t\t\tcase \"dcim.region\":\n\t\t\t\tmapping[\"region_id\"] = scopeID\n\t\t\t}\n\t\t}\n\t\tmapping[\"status\"] = v.Status.Value\n\t\tmapping[\"tags\"] = getTagListFromNestedTagList(v.Tags)\n\n\t\tcf := flattenCustomFields(v.CustomFields)\n\t\tif cf != nil {\n\t\t\tmapping[customFieldsKey] = cf\n\t\t}\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"prefixes\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_prefixes_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxPrefixesDataSource_basic(t *testing.T) {\n\ttestPrefixes := []string{\"10.0.4.0/24\", \"10.0.5.0/24\", \"10.0.6.0/24\", \"10.0.7.0/24\", \"10.0.8.0/24\", \"10.0.9.0/24\"}\n\ttestSlug := \"prefixes_ds_basic\"\n\ttestVlanVids := []int{4093, 4094}\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_prefix\" \"test_prefix1\" {\n  prefix      = \"%[2]s\"\n  status      = \"active\"\n  description = \"my-description\"\n  vrf_id      = netbox_vrf.test_vrf.id\n  vlan_id     = netbox_vlan.test_vlan1.id\n  tags        = [netbox_tag.test_tag1.slug]\n}\n\nresource \"netbox_prefix\" \"test_prefix2\" {\n  prefix  = \"%[3]s\"\n  status  = \"container\"\n  vrf_id  = netbox_vrf.test_vrf.id\n  vlan_id = netbox_vlan.test_vlan2.id\n}\n\nresource \"netbox_prefix\" \"without_vrf_and_vlan\" {\n  prefix = \"%[4]s\"\n  status = \"container\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s_tenant\"\n}\n\nresource \"netbox_prefix\" \"with_tenant_id\" {\n  prefix    = \"%[5]s\"\n  status    = \"container\"\n  tenant_id = netbox_tenant.test.id\n}\n\nresource \"netbox_site\" \"test\" {\n  name     = \"site-%[1]s\"\n  timezone = \"Europe/Berlin\"\n}\n\nresource \"netbox_prefix\" \"with_site_id\" {\n  prefix  = \"%[6]s\"\n  status  = \"container\"\n  site_id    = netbox_site.test.id\n}\n\nresource \"netbox_site\" \"test2\" {\n  name     = \"site2-%[1]s\"\n  timezone = \"Europe/Berlin\"\n}\n\nresource \"netbox_prefix\" \"with_container\" {\n  prefix  = \"%[9]s\"\n  status  = \"container\"\n  site_id    = netbox_site.test2.id\n}\n\nresource \"netbox_vrf\" \"test_vrf\" {\n  name = \"%[1]s_test_vrf\"\n}\n\nresource \"netbox_vlan\" \"test_vlan1\" {\n  name = \"%[1]s_vlan1\"\n  vid  = %[7]d\n}\n\nresource \"netbox_vlan\" \"test_vlan2\" {\n  name = \"%[1]s_vlan2\"\n  vid  = %[8]d\n}\n\nresource \"netbox_tag\" \"test_tag1\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"test_tag2\" {\n  name = \"tag-with-no-associations\"\n}\n\ndata \"netbox_prefixes\" \"by_vrf\" {\n  depends_on = [netbox_prefix.test_prefix1, netbox_prefix.test_prefix2]\n  filter {\n    name  = \"vrf_id\"\n    value = netbox_vrf.test_vrf.id\n  }\n}\n\ndata \"netbox_prefixes\" \"by_vid\" {\n  depends_on = [netbox_prefix.test_prefix1, netbox_prefix.test_prefix2]\n  filter {\n    name  = \"vlan_vid\"\n    value = \"%[7]d\"\n  }\n}\n\ndata \"netbox_prefixes\" \"by_tag\" {\n  depends_on = [netbox_prefix.test_prefix1]\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s\"\n  }\n}\n\ndata \"netbox_prefixes\" \"by_status\" {\n  depends_on = [netbox_prefix.test_prefix1]\n  filter {\n    name  = \"status\"\n    value = \"active\"\n  }\n}\n\ndata \"netbox_prefixes\" \"no_results\" {\n  depends_on = [netbox_prefix.test_prefix1]\n  filter {\n    name  = \"tag\"\n    value = netbox_tag.test_tag2.name\n  }\n}\n\ndata \"netbox_prefixes\" \"find_prefix_without_vrf_and_vlan\" {\n  depends_on = [netbox_prefix.without_vrf_and_vlan]\n  filter {\n    name  = \"prefix\"\n    value = netbox_prefix.without_vrf_and_vlan.prefix\n  }\n}\n\ndata \"netbox_prefixes\" \"find_prefix_with_tenant_id\" {\n  depends_on = [netbox_prefix.with_tenant_id]\n  filter {\n    name  = \"tenant_id\"\n    value = netbox_tenant.test.id\n  }\n}\n\ndata \"netbox_prefixes\" \"find_prefix_with_site_id\" {\n  depends_on = [netbox_prefix.with_site_id]\n  filter {\n    name  = \"site_id\"\n    value = netbox_site.test.id\n  }\n}\n\ndata \"netbox_prefixes\" \"find_prefix_with_contains\" {\n  depends_on = [netbox_prefix.with_container]\n  filter {\n    name  = \"contains\"\n    value = \"10.0.9.50\"\n  }\n}\n\ndata \"netbox_prefixes\" \"find_prefix_with_description\" {\n  depends_on = [netbox_prefix.test_prefix1]\n  filter {\n    name  = \"description\"\n    value = netbox_prefix.test_prefix1.description\n  }\n}\n\n\n`, testName, testPrefixes[0], testPrefixes[1], testPrefixes[2], testPrefixes[3], testPrefixes[4], testVlanVids[0], testVlanVids[1], testPrefixes[5]),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.by_vrf\", \"prefixes.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefixes.by_vrf\", \"prefixes.1.vlan_vid\", \"netbox_vlan.test_vlan2\", \"vid\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_prefixes.by_vid\", \"prefixes.0.vlan_vid\", \"netbox_vlan.test_vlan1\", \"vid\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.by_tag\", \"prefixes.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.by_tag\", \"prefixes.0.description\", \"my-description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.by_status\", \"prefixes.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.by_status\", \"prefixes.0.description\", \"my-description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.no_results\", \"prefixes.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.find_prefix_with_tenant_id\", \"prefixes.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.find_prefix_with_tenant_id\", \"prefixes.0.prefix\", \"10.0.7.0/24\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.find_prefix_with_site_id\", \"prefixes.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.find_prefix_with_site_id\", \"prefixes.0.prefix\", \"10.0.8.0/24\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.find_prefix_with_contains\", \"prefixes.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.find_prefix_with_contains\", \"prefixes.0.prefix\", \"10.0.9.0/24\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_prefixes.find_prefix_with_contains\", \"prefixes.0.site_id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.find_prefix_with_description\", \"prefixes.0.description\", \"my-description\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPrefixesDataSource_customFields(t *testing.T) {\n\ttestSlug := \"prefixes_ds_custom_fields\"\n\ttestName := testAccGetTestName(testSlug)\n\t// Custom field names can only contain alphanumeric characters and underscores\n\ttestFieldPrefix := \"tf_test_cf\"\n\ttestPrefix := \"10.100.0.0/24\"\n\ttestGatewayIP := \"10.100.0.1/24\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n# Create a text custom field (simple type)\nresource \"netbox_custom_field\" \"test_text\" {\n  name          = \"%[4]s_text\"\n  type          = \"text\"\n  content_types = [\"ipam.prefix\"]\n}\n\n# Create a JSON custom field (can store complex objects like IP addresses)\n# Note: Object type custom fields are available in NetBox v4.0+, but this provider\n# version is tested against v4.2.2 which doesn't fully support them yet.\n# JSON fields can be used as a workaround for complex data structures.\nresource \"netbox_custom_field\" \"test_json\" {\n  name          = \"%[4]s_json\"\n  type          = \"json\"\n  content_types = [\"ipam.prefix\"]\n}\n\n# Create a prefix with custom fields\nresource \"netbox_prefix\" \"test_with_custom_fields\" {\n  prefix = \"%[2]s\"\n  status = \"active\"\n  custom_fields = {\n    (netbox_custom_field.test_text.name) = \"test-value\"\n    (netbox_custom_field.test_json.name) = jsonencode({\n      gateway = {\n        address = \"%[3]s\"\n        family  = \"IPv4\"\n      }\n    })\n  }\n  depends_on = [\n    netbox_custom_field.test_text,\n    netbox_custom_field.test_json,\n  ]\n}\n\n# Data source to fetch the prefix with custom fields\ndata \"netbox_prefixes\" \"with_custom_fields\" {\n  depends_on = [netbox_prefix.test_with_custom_fields]\n  filter {\n    name  = \"prefix\"\n    value = netbox_prefix.test_with_custom_fields.prefix\n  }\n}\n\n# Output to test that custom_fields can be accessed\noutput \"custom_fields_output\" {\n  value = length(data.netbox_prefixes.with_custom_fields.prefixes) > 0 ? data.netbox_prefixes.with_custom_fields.prefixes[0].custom_fields : {}\n}\n\n# Output to test contains() function with keys() for simple field\noutput \"has_text_field\" {\n  value = (\n    length(data.netbox_prefixes.with_custom_fields.prefixes) > 0 &&\n    contains(\n      keys(data.netbox_prefixes.with_custom_fields.prefixes[0].custom_fields),\n      \"%[4]s_text\"\n    )\n  )\n}\n\n# Output to test contains() function with keys() for complex JSON field\noutput \"has_json_field\" {\n  value = (\n    length(data.netbox_prefixes.with_custom_fields.prefixes) > 0 &&\n    contains(\n      keys(data.netbox_prefixes.with_custom_fields.prefixes[0].custom_fields),\n      \"%[4]s_json\"\n    )\n  )\n}\n\n# Test that JSON field can be parsed (it will be a JSON string containing JSON)\noutput \"json_field_is_valid\" {\n  value = (\n    length(data.netbox_prefixes.with_custom_fields.prefixes) > 0 &&\n    can(jsondecode(data.netbox_prefixes.with_custom_fields.prefixes[0].custom_fields[\"%[4]s_json\"]))\n  )\n}\n`, testName, testPrefix, testGatewayIP, testFieldPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\t// Verify we got one prefix\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.with_custom_fields\", \"prefixes.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.with_custom_fields\", \"prefixes.0.prefix\", testPrefix),\n\n\t\t\t\t\t// Verify custom_fields attribute exists and is set\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_prefixes.with_custom_fields\", \"prefixes.0.custom_fields.%\"),\n\n\t\t\t\t\t// Verify simple custom field values\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_prefixes.with_custom_fields\", fmt.Sprintf(\"prefixes.0.custom_fields.%s_text\", testFieldPrefix), \"test-value\"),\n\n\t\t\t\t\t// Verify complex JSON field exists and is a JSON string\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"data.netbox_prefixes.with_custom_fields\", fmt.Sprintf(\"prefixes.0.custom_fields.%s_json\", testFieldPrefix)),\n\n\t\t\t\t\t// Verify outputs work for simple fields\n\t\t\t\t\tresource.TestCheckOutput(\"has_text_field\", \"true\"),\n\n\t\t\t\t\t// Verify outputs work for complex JSON field - this tests flattenCustomFields works!\n\t\t\t\t\tresource.TestCheckOutput(\"has_json_field\", \"true\"),\n\t\t\t\t\tresource.TestCheckOutput(\"json_field_is_valid\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_rack_role.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxRackRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxRackRoleRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchemaRead,\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxRackRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := dcim.NewDcimRackRolesListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Dcim.DcimRackRolesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one rack role returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no rack role found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"description\", result.Description)\n\td.Set(\"color_hex\", result.Color)\n\td.Set(tagsKey, getTagListFromNestedTagList(result.Tags))\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_rack_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxRackRoleDataSource_basic(t *testing.T) {\n\ttestSlug := \"rack_role_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_rack_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n\tdescription = \"%[1]sdescription\"\n  tags = [netbox_tag.test.name]\n}\n\ndata \"netbox_rack_role\" \"test\" {\n  depends_on = [netbox_rack_role.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_rack_role.test\", \"id\", \"netbox_rack_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_rack_role.test\", \"name\", \"netbox_rack_role.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_rack_role.test\", \"color_hex\", \"netbox_rack_role.test\", \"color_hex\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_rack_role.test\", \"description\", \"netbox_rack_role.test\", \"description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_rack_role.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_rack_role.test\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_racks.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxRacks() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxRacksRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"racks\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"width\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"u_height\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttagsKey: tagsSchemaRead,\n\t\t\t\t\t\t\"tenant_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"facility_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"location_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"serial\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"asset_tag\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"type_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"weight\": {\n\t\t\t\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"max_weight\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"weight_unit\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"desc_units\": {\n\t\t\t\t\t\t\tType:     schema.TypeBool,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"outer_width\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"outer_depth\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"outer_unit\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mounting_depth\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"comments\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"custom_fields\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxRacksRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := dcim.NewDcimRacksListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"asset_tag\":\n\t\t\t\tparams.AssetTag = &vString\n\t\t\tcase \"contact\":\n\t\t\t\tparams.Contact = &vString\n\t\t\tcase \"contact_group\":\n\t\t\t\tparams.ContactGroup = &vString\n\t\t\tcase \"contact_role\":\n\t\t\t\tparams.ContactRole = &vString\n\t\t\tcase \"desc_units\":\n\t\t\t\tparams.DescUnits = &vString\n\t\t\tcase \"facility_id\":\n\t\t\t\tparams.FacilityID = &vString\n\t\t\tcase \"id\":\n\t\t\t\tparams.ID = &vString\n\t\t\tcase \"location_id\":\n\t\t\t\tparams.LocationID = &vString\n\t\t\tcase \"max_weight\":\n\t\t\t\tparams.MaxWeight = &vString\n\t\t\tcase \"mounting_depth\":\n\t\t\t\tparams.MountingDepth = &vString\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"outer_depth\":\n\t\t\t\tparams.OuterDepth = &vString\n\t\t\tcase \"outer_unit\":\n\t\t\t\tparams.OuterUnit = &vString\n\t\t\tcase \"outer_width\":\n\t\t\t\tparams.OuterWidth = &vString\n\t\t\tcase \"region_id\":\n\t\t\t\tparams.RegionID = &vString\n\t\t\tcase \"role_id\":\n\t\t\t\tparams.RoleID = &vString\n\t\t\tcase \"serial\":\n\t\t\t\tparams.Serial = &vString\n\t\t\tcase \"site_id\":\n\t\t\t\tparams.SiteID = &vString\n\t\t\tcase \"status\":\n\t\t\t\tparams.Status = &vString\n\t\t\tcase \"tenant_id\":\n\t\t\t\tparams.TenantID = &vString\n\t\t\tcase \"type_id\":\n\t\t\t\tparams.Type = &vString\n\t\t\tcase \"u_height\":\n\t\t\t\tparams.UHeight = &vString\n\t\t\tcase \"weight\":\n\t\t\t\tparams.Weight = &vString\n\t\t\tcase \"weight_unit\":\n\t\t\t\tparams.WeightUnit = &vString\n\t\t\tcase \"width\":\n\t\t\t\tparams.Width = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allRacks []*models.Rack\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Dcim.DcimRacksList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch racks at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallRacks = append(allRacks, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allRacks)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allRacks))\n\tfilteredRacks := allRacks[:trimmedCount]\n\n\tif len(filteredRacks) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredRacks {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = v.ID\n\t\tmapping[\"name\"] = v.Name\n\t\tif v.Site != nil {\n\t\t\tmapping[\"site_id\"] = v.Site.ID\n\t\t}\n\t\tif v.Status != nil {\n\t\t\tmapping[\"status\"] = v.Status.Value\n\t\t}\n\t\tif v.Width != nil {\n\t\t\tmapping[\"width\"] = v.Width.Value\n\t\t}\n\t\tmapping[\"u_height\"] = v.UHeight\n\t\tmapping[\"tags\"] = getTagListFromNestedTagList(v.Tags)\n\t\tif v.Tenant != nil {\n\t\t\tmapping[\"tenant_id\"] = v.Tenant.ID\n\t\t}\n\t\tmapping[\"facility_id\"] = v.FacilityID\n\t\tif v.Location != nil {\n\t\t\tmapping[\"location_id\"] = v.Location.ID\n\t\t}\n\t\tif v.Role != nil {\n\t\t\tmapping[\"role_id\"] = v.Role.ID\n\t\t}\n\t\tmapping[\"serial\"] = v.Serial\n\t\tmapping[\"asset_tag\"] = v.AssetTag\n\t\tmapping[\"type_id\"] = v.Type\n\t\tmapping[\"weight\"] = v.Weight\n\t\tmapping[\"max_weight\"] = v.MaxWeight\n\t\tmapping[\"desc_units\"] = v.DescUnits\n\t\tmapping[\"outer_width\"] = v.OuterWidth\n\t\tmapping[\"outer_depth\"] = v.OuterDepth\n\t\tif v.OuterUnit != nil {\n\t\t\tmapping[\"outer_unit\"] = v.OuterUnit.Value\n\t\t}\n\t\tmapping[\"mounting_depth\"] = v.MountingDepth\n\t\tmapping[\"description\"] = v.Description\n\t\tmapping[\"comments\"] = v.Comments\n\t\tmapping[\"custom_fields\"] = getCustomFields(v.CustomFields)\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"racks\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_racks_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxRacksDataSource_basic(t *testing.T) {\n\ttestRacks := []string{\"rack1\", \"rack2\", \"rack3\"}\n\ttestSlug := \"racks_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_rack\" \"test_rack1\" {\n  name     = \"%[2]s\"\n  site_id  = netbox_site.test.id\n  status   = \"active\"\n  width    = 10\n  u_height = 40\n}\n\nresource \"netbox_rack\" \"test_rack2\" {\n  name     = \"%[3]s\"\n  site_id  = netbox_site.test.id\n  status   = \"active\"\n  width    = 19\n  u_height = 41\n}\n\nresource \"netbox_rack\" \"test_rack3\" {\n  name     = \"%[4]s\"\n  site_id  = netbox_site.test.id\n  status   = \"reserved\"\n  width    = 21\n  u_height = 42\n}\n\ndata \"netbox_racks\" \"by_name\" {\n  depends_on = [netbox_rack.test_rack1, netbox_rack.test_rack2, netbox_rack.test_rack3]\n  filter {\n    name  = \"name\"\n    value = netbox_rack.test_rack3.name\n  }\n  filter {\n    name = \"site_id\"\n    value = netbox_site.test.id\n  }\n}\n\ndata \"netbox_racks\" \"by_status\" {\n  depends_on = [netbox_rack.test_rack1, netbox_rack.test_rack2, netbox_rack.test_rack3]\n  filter {\n    name  = \"status\"\n    value = \"active\"\n  }\n  filter {\n    name = \"site_id\"\n    value = netbox_site.test.id\n  }\n}\n`, testName, testRacks[0], testRacks[1], testRacks[2]),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_racks.by_name\", \"racks.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_racks.by_status\", \"racks.#\", \"2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_region.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxRegion() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxRegionRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"parent_region_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxRegionRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := dcim.NewDcimRegionsListParams()\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tid := f.(map[string]interface{})[\"id\"]\n\t\t\tif id != nil {\n\t\t\t\tvID := id.(int)\n\t\t\t\tif vID != 0 {\n\t\t\t\t\tvIDString := strconv.Itoa(vID)\n\t\t\t\t\tparams.ID = &vIDString\n\t\t\t\t}\n\t\t\t}\n\t\t\tname := f.(map[string]interface{})[\"name\"]\n\t\t\tif name != nil {\n\t\t\t\tvName := name.(string)\n\t\t\t\tparams.Name = &vName\n\t\t\t}\n\t\t\tslug := f.(map[string]interface{})[\"slug\"]\n\t\t\tif slug != nil {\n\t\t\t\tvSlug := slug.(string)\n\t\t\t\tparams.Slug = &vSlug\n\t\t\t}\n\t\t}\n\t}\n\n\tres, err := api.Dcim.DcimRegionsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one region returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no region found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"description\", result.Description)\n\tif result.Parent != nil {\n\t\td.Set(\"parent_region_id\", result.Parent.ID)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_region_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxRegionDataSource_basic(t *testing.T) {\n\ttestSlug := \"region_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\nresource \"netbox_region\" \"test\" {\n  name = \"%[1]s\"\n}\ndata \"netbox_region\" \"test\" {\n  depends_on = [netbox_region.test]\n  filter {\n\tname = \"%[1]s\"\n  }\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_region.test\", \"id\", \"netbox_region.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_region.test\", \"slug\", \"netbox_region.test\", \"slug\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxRegionDataSource_parent(t *testing.T) {\n\ttestSlug := \"region_ds_parent\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\nresource \"netbox_region\" \"test\" {\n  name = \"%[1]s\"\n}\nresource \"netbox_region\" \"test-child\" {\n  name             = \"%[1]s-child\"\n  parent_region_id = netbox_region.test.id\n}\ndata \"netbox_region\" \"test-child\" {\n  depends_on = [netbox_region.test-child]\n  filter {\n\tname = \"%[1]s-child\"\n  }\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_region.test-child\", \"id\", \"netbox_region.test-child\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_region.test-child\", \"parent_region_id\", \"netbox_region.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_rir.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxRir() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead: dataSourceNetboxRirRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs):\n\n> Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which \"owns\" certain address space.`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"is_private\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxRirRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamRirsListParams()\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.Name = &name\n\t}\n\n\tif slug, ok := d.Get(\"slug\").(string); ok && slug != \"\" {\n\t\tparams.Slug = &slug\n\t}\n\n\tres, err := api.Ipam.IpamRirsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one rir returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no rir found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.Set(\"id\", result.ID)\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"description\", result.Description)\n\td.Set(\"is_private\", result.IsPrivate)\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_rir_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxRirSetUp(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_rir\" \"test\" {\n  name = \"%[1]s\"\n}`, testName)\n}\n\nconst testAccNetboxRirNoResult = `\ndata \"netbox_rir\" \"test\" {\n  name = \"nonexistent\"\n}`\n\nfunc testAccNetboxRirByName(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_rir\" \"test\" {\n  name = \"%s\"\n}`, testName)\n}\n\nfunc testAccNetboxRirBySlug(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_rir\" \"test\" {\n  slug = \"%[1]s\"\n}`, testName)\n}\n\nfunc TestAccNetboxRirDataSource_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"rir_ds_basic\")\n\tsetUp := testAccNetboxRirSetUp(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test\", \"name\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + testAccNetboxRirNoResult,\n\t\t\t\tExpectError: regexp.MustCompile(\"no rir found matching filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxRirByName(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_rir.test\", \"id\", \"netbox_rir.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxRirBySlug(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_rir.test\", \"id\", \"netbox_rir.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_rir.test\", \"name\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_route_target.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxRouteTarget() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxRouteTargetRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 21),\n\t\t\t\tRequired:     true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxRouteTargetRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tparams := ipam.NewIpamRouteTargetsListParams()\n\tparams.Name = &name\n\n\tlimit := int64(2)\n\tparams.Limit = &limit\n\n\tres, err := api.Ipam.IpamRouteTargetsList(params, nil)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one route target returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no route target found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\tif result.Tenant != nil {\n\t\td.Set(\"tenant_id\", result.Tenant.ID)\n\t}\n\tif result.Description != \"\" {\n\t\td.Set(\"description\", result.Description)\n\t}\n\tif result.Tags != nil {\n\t\td.Set(tagsKey, result.Tags)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_route_target_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc getNetboxDataSourceRouteTargetConfig(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"acctest_ds_rt\" {\n\tname = \"%[1]s\"\n}\n\nresource \"netbox_route_target\" \"acctest_ds_rt\" {\n\tname = \"%[1]s\"\n\ttenant_id = netbox_tenant.acctest_ds_rt.id\n}\n\ndata \"netbox_route_target\" \"acctest_ds_rt\" {\n\tname = \"%[1]s\"\n\tdepends_on = [netbox_route_target.acctest_ds_rt]\n}`, testName)\n}\n\nfunc TestAccNetboxRouteTarget_basic(t *testing.T) {\n\ttestSlug := \"rtds\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: getNetboxDataSourceRouteTargetConfig(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_route_target.acctest_ds_rt\", \"id\", \"netbox_route_target.acctest_ds_rt\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_site.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxSite() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxSiteRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"id\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"facility\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"asn_ids\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"region_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"time_zone\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"physical_address\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxSiteRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := dcim.NewDcimSitesListParams()\n\n\tparams.Limit = int64ToPtr(2)\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.SetName(&name)\n\t}\n\tif slug, ok := d.Get(\"slug\").(string); ok && slug != \"\" {\n\t\tparams.SetSlug(&slug)\n\t}\n\tif id, ok := d.Get(\"id\").(string); ok && id != \"0\" {\n\t\tparams.SetID(&id)\n\t}\n\tif facility, ok := d.Get(\"facility\").(string); ok && facility != \"\" {\n\t\tparams.SetFacility(&facility)\n\t}\n\n\tres, err := api.Dcim.DcimSitesList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one site returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no site found matching filter\")\n\t}\n\n\tsite := res.GetPayload().Results[0]\n\n\td.SetId(strconv.FormatInt(site.ID, 10))\n\td.Set(\"asn_ids\", getIDsFromNestedASNList(site.Asns))\n\td.Set(\"comments\", site.Comments)\n\td.Set(\"description\", site.Description)\n\td.Set(\"name\", site.Name)\n\td.Set(\"site_id\", site.ID)\n\td.Set(\"slug\", site.Slug)\n\td.Set(\"time_zone\", site.TimeZone)\n\td.Set(\"facility\", site.Facility)\n\td.Set(\"physical_address\", site.PhysicalAddress)\n\n\tif site.Group != nil {\n\t\td.Set(\"group_id\", site.Group.ID)\n\t}\n\tif site.Region != nil {\n\t\td.Set(\"region_id\", site.Region.ID)\n\t}\n\tif site.Status != nil {\n\t\td.Set(\"status\", site.Status.Value)\n\t}\n\tif site.Tenant != nil {\n\t\td.Set(\"tenant_id\", site.Tenant.ID)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_site_group.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxSiteGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxSiteGroupRead,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tComputed:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxSiteGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := dcim.NewDcimSiteGroupsListParams()\n\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.Name = &name\n\t}\n\n\tif slug, ok := d.Get(\"slug\").(string); ok && slug != \"\" {\n\t\tparams.Slug = &slug\n\t}\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Dcim.DcimSiteGroupsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one site group returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no site group found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"description\", result.Description)\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_site_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxSiteGroupDataSource_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"sitegrp_ds_basic\")\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site_group\" \"test\" {\n  name = \"%[1]s\"\n  description = \"foo\"\n}\n\ndata \"netbox_site_group\" \"by_name\" {\n  depends_on = [netbox_site_group.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_site_group.by_name\", \"id\", \"netbox_site_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_site_group.by_name\", \"name\", \"netbox_site_group.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_site_group.by_name\", \"description\", \"foo\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_site_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxSiteSetUp(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_rir\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_asn\" \"test\" {\n  asn = 234\n  rir_id = netbox_rir.test.id\n}\n\nresource \"netbox_region\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  asn_ids = [netbox_asn.test.id]\n  description = \"Test\"\n  region_id = netbox_region.test.id\n  tenant_id = netbox_tenant.test.id\n  timezone = \"Europe/Berlin\"\n  facility = \"Facility\"\n\tphysical_address = \"Platz d. Republik 1, 10557 Berlin, Germany\"\n}`, testName)\n}\n\nconst testAccNetboxSiteNoResult = `\ndata \"netbox_site\" \"test\" {\n  name = \"_does_not_exist_\"\n}`\n\nfunc testAccNetboxSiteByName(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}`, testName)\n}\n\nfunc testAccNetboxSiteBySlug(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_site\" \"test\" {\n  slug = \"%[1]s\"\n}`, testName)\n}\n\nfunc testAccNetboxSiteByID() string {\n\treturn `\ndata \"netbox_site\" \"test\" {\n  id = netbox_site.test.id\n}`\n}\n\nfunc testAccNetboxSiteByFacility() string {\n\treturn `\ndata \"netbox_site\" \"test\" {\n  facility = netbox_site.test.facility\n}`\n}\n\nfunc TestAccNetboxSiteDataSource_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"site_ds_basic\")\n\tsetUp := testAccNetboxSiteSetUp(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"slug\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + testAccNetboxSiteNoResult,\n\t\t\t\tExpectError: regexp.MustCompile(\"no site found matching filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxSiteByName(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_site.test\", \"id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxSiteBySlug(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_site.test\", \"id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"asn_ids.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_site.test\", \"asn_ids.0\", \"netbox_asn.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_site.test\", \"description\", \"Test\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_site.test\", \"time_zone\", \"Europe/Berlin\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_site.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_site.test\", \"physical_address\", \"Platz d. Republik 1, 10557 Berlin, Germany\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_site.test\", \"region_id\", \"netbox_region.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_site.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxSiteByID(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_site.test\", \"id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxSiteByFacility(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_site.test\", \"id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tag.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxTag() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxTagRead,\n\t\tDescription: `:meta:subcategory:Extras:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxTagRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := extras.NewExtrasTagsListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Extras.ExtrasTagsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one tag returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no tag found matching filter\")\n\t}\n\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"description\", result.Description)\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tags.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxTags() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxTagsRead,\n\t\tDescription: `:meta:subcategory:Extras:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"tags\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"tag_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"color\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tOptional: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxTagsRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := extras.NewExtrasTagsListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tfilterParams := filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"id\":\n\t\t\t\tparams.ID = &vString\n\t\t\tcase \"id__gt\":\n\t\t\t\tparams.IDGt = &vString\n\t\t\tcase \"id__gte\":\n\t\t\t\tparams.IDGte = &vString\n\t\t\tcase \"id__lt\":\n\t\t\t\tparams.IDLt = &vString\n\t\t\tcase \"id__lte\":\n\t\t\t\tparams.IDLte = &vString\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"name__ic\":\n\t\t\t\tparams.NameIc = &vString\n\t\t\tcase \"name__niew\":\n\t\t\t\tparams.NameNiew = &vString\n\t\t\tcase \"name__iew\":\n\t\t\t\tparams.NameIew = &vString\n\t\t\tcase \"name__nisw\":\n\t\t\t\tparams.NameNisw = &vString\n\t\t\tcase \"name__isw\":\n\t\t\t\tparams.NameIsw = &vString\n\t\t\tcase \"slug\":\n\t\t\t\tparams.Slug = &vString\n\t\t\tcase \"slug__ic\":\n\t\t\t\tparams.SlugIc = &vString\n\t\t\tcase \"slug__niew\":\n\t\t\t\tparams.SlugNiew = &vString\n\t\t\tcase \"slug__iew\":\n\t\t\t\tparams.SlugIew = &vString\n\t\t\tcase \"slug__nisw\":\n\t\t\t\tparams.SlugNisw = &vString\n\t\t\tcase \"slug__isw\":\n\t\t\t\tparams.SlugIsw = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allTags []*models.Tag\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Extras.ExtrasTagsList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch tags at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallTags = append(allTags, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allTags)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allTags))\n\tresults := allTags[:trimmedCount]\n\n\tif len(results) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range results {\n\t\tmapping := make(map[string]interface{})\n\n\t\tmapping[\"tag_id\"] = v.ID\n\t\tmapping[\"name\"] = v.Name\n\t\tmapping[\"slug\"] = v.Slug\n\t\tmapping[\"description\"] = v.Description\n\t\tmapping[\"color\"] = v.Color\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"tags\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tags_test.go",
    "content": "package netbox\n\nimport (\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxTagsSetUp() string {\n\treturn `\nresource \"netbox_tag\" \"test_1\" {\n  name = \"Tag1234\"\n  slug = \"tag1234\"\n}\n\nresource \"netbox_tag\" \"test_2\" {\n  name = \"Tag1235\"\n  slug = \"tag1235\"\n}\n\nresource \"netbox_tag\" \"test_3\" {\n  name = \"Tag2345\"\n  slug = \"weird\"\n}`\n}\n\nfunc testAccNetboxTagsByName() string {\n\treturn `\ndata \"netbox_tags\" \"test\" {\n  filter {\n    name  = \"name\"\n    value = \"Tag1234\"\n  }\n}`\n}\n\nfunc testAccNetboxTagsBySlug() string {\n\treturn `\ndata \"netbox_tags\" \"test\" {\n  filter {\n    name = \"slug\"\n    value = \"weird\"\n  }\n}`\n}\n\n// func testAccNetboxTagsAll() string {\n// \treturn `\n// data \"netbox_tags\" \"test\" {\n// }`\n// }\n\nfunc TestAccNetboxTagsDataSource_basic(t *testing.T) {\n\tsetUp := testAccNetboxTagsSetUp()\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tag.test_1\", \"slug\", \"tag1234\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxTagsByName(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_tags.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tags.test\", \"tags.0.tag_id\", \"netbox_tag.test_1\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxTagsBySlug(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_tags.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tags.test\", \"tags.0.tag_id\", \"netbox_tag.test_3\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// {\n\t\t\t// \tConfig: setUp + testAccNetboxTagsAll(),\n\t\t\t// \tCheck: resource.ComposeTestCheckFunc(\n\t\t\t// \t\tresource.TestCheckResourceAttr(\"data.netbox_tags.test\", \"tags.#\", \"3\"),\n\t\t\t// \t\tresource.TestCheckResourceAttrPair(\"data.netbox_tags.test\", \"tags.0.tag_id\", \"netbox_tag.test_1\", \"id\"),\n\t\t\t// \t\tresource.TestCheckResourceAttrPair(\"data.netbox_tags.test\", \"tags.1.tag_id\", \"netbox_tag.test_2\", \"id\"),\n\t\t\t// \t\tresource.TestCheckResourceAttrPair(\"data.netbox_tags.test\", \"tags.2.tag_id\", \"netbox_tag.test_3\", \"id\"),\n\t\t\t// \t),\n\t\t\t// },\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tenant.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxTenant() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxTenantRead,\n\t\tDescription: `:meta:subcategory:Tenancy:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tComputed:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: []string{\"name\", \"slug\"},\n\t\t\t},\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxTenantRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := tenancy.NewTenancyTenantsListParams()\n\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.Name = &name\n\t}\n\n\tif slug, ok := d.Get(\"slug\").(string); ok && slug != \"\" {\n\t\tparams.Slug = &slug\n\t}\n\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Tenancy.TenancyTenantsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one tenant returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no tenant found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"description\", result.Description)\n\tif result.Group != nil {\n\t\td.Set(\"group_id\", result.Group.ID)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tenant_group.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxTenantGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxTenantGroupRead,\n\t\tDescription: `:meta:subcategory:Tenancy:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxTenantGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := tenancy.NewTenancyTenantGroupsListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tres, err := api.Tenancy.TenancyTenantGroupsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one tenant group returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no tenant group found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"description\", result.Description)\n\tif result.Parent != nil {\n\t\td.Set(\"parent_id\", result.Parent.ID)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tenant_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxTenantDataGroupSource_basic(t *testing.T) {\n\ttestSlug := \"tntgrp_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\ndata \"netbox_tenant_group\" \"test\" {\n  depends_on = [netbox_tenant_group.test]\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenant_group.test\", \"id\", \"netbox_tenant_group.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tenant_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxTenantDataSource_basic(t *testing.T) {\n\ttestSlug := \"tnt_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\ndata \"netbox_tenant\" \"by_name\" {\n  depends_on = [netbox_tenant.test]\n  name = \"%[1]s\"\n}\n\ndata \"netbox_tenant\" \"by_slug\" {\n  depends_on = [netbox_tenant.test]\n  slug = \"%[1]s\"\n}\n\ndata \"netbox_tenant\" \"by_description\" {\n  depends_on = [netbox_tenant.test]\n  name = \"%[1]s\"\n  description = \"%[1]s\"\n}\n\ndata \"netbox_tenant\" \"by_both\" {\n  depends_on = [netbox_tenant.test]\n  name = \"%[1]s\"\n  slug = \"%[1]s\"\n  description = \"%[1]s\"\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenant.by_name\", \"id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenant.by_slug\", \"id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenant.by_description\", \"id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenant.by_both\", \"id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tenants.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxTenants() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxTenantsRead,\n\t\tDescription: `:meta:subcategory:Tenancy:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"tenants\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"created\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"last_updated\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"comments\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"custom_fields\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\"site_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"rack_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"device_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vrf_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"prefix_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"ip_address_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vlan_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vm_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"circuit_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"cluster_count\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tenant_group\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"tenant_count\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxTenantsRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := tenancy.NewTenancyTenantsListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"slug\":\n\t\t\t\tparams.Slug = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allTenants []*models.Tenant\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Tenancy.TenancyTenantsList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch tenants at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallTenants = append(allTenants, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allTenants)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allTenants))\n\tfilteredTenants := allTenants[:trimmedCount]\n\n\tif len(filteredTenants) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredTenants {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = v.ID\n\t\tmapping[\"name\"] = v.Name\n\t\tmapping[\"slug\"] = v.Slug\n\t\tmapping[\"description\"] = v.Description\n\t\tmapping[\"created\"] = v.Created.String()\n\t\tmapping[\"last_updated\"] = v.LastUpdated.String()\n\t\tmapping[\"comments\"] = v.Comments\n\t\tmapping[\"custom_fields\"] = flattenCustomFields(v.CustomFields)\n\n\t\tmapping[\"site_count\"] = v.SiteCount\n\t\tmapping[\"rack_count\"] = v.RackCount\n\t\tmapping[\"device_count\"] = v.DeviceCount\n\t\tmapping[\"vrf_count\"] = v.VrfCount\n\t\tmapping[\"prefix_count\"] = v.PrefixCount\n\t\tmapping[\"ip_address_count\"] = v.IpaddressCount\n\t\tmapping[\"vlan_count\"] = v.VlanCount\n\t\tmapping[\"vm_count\"] = v.VirtualmachineCount\n\t\tmapping[\"circuit_count\"] = v.CircuitCount\n\t\tmapping[\"cluster_count\"] = v.ClusterCount\n\n\t\tmapping[\"tenant_group\"] = flattenTenantGroup(v.Group)\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"tenants\", s)\n}\n\nfunc flattenTenantGroup(group *models.NestedTenantGroup) []map[string]interface{} {\n\tvar s []map[string]interface{}\n\tif group != nil {\n\t\tvar mapping = make(map[string]interface{})\n\t\tmapping[\"id\"] = group.ID\n\t\tmapping[\"name\"] = group.Name\n\t\tmapping[\"slug\"] = group.Slug\n\t\tmapping[\"tenant_count\"] = group.TenantCount\n\t\ts = append(s, mapping)\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_tenants_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxTenantsDataSource_basic(t *testing.T) {\n\ttestSlug := \"tnts_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant\" \"test_list_0\" {\n  name = \"%[1]s_0\"\n}\nresource \"netbox_tenant\" \"test_list_1\" {\n  name = \"%[1]s_1\"\n}\ndata \"netbox_tenants\" \"test\" {\n  depends_on = [netbox_tenant.test_list_0, netbox_tenant.test_list_1]\n}`, testName),\n\t\t\t\t//                              This snippet sometimes returns things from other tests, even if resource.Test is used instead of resource.ParallelTest\n\t\t\t\t//                              This happens especially in CI testing (where test execution is presumably slow)\n\t\t\t\t//                              The check functions are now removed so this does no longer happen\n\t\t\t\t//\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t//\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenants.test\", \"tenants.0.name\", \"netbox_tenant.test_list_0\", \"name\"),\n\t\t\t\t//\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenants.test\", \"tenants.1.name\", \"netbox_tenant.test_list_1\", \"name\"),\n\t\t\t\t//\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxTenantsDataSource_filter(t *testing.T) {\n\ttestSlug := \"tnts_ds_filter\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant\" \"test_list_0\" {\n  name = \"%[1]s_0\"\n}\nresource \"netbox_tenant\" \"test_list_1\" {\n  name = \"%[1]s_1\"\n}\ndata \"netbox_tenants\" \"test\" {\n  depends_on = [netbox_tenant.test_list_0, netbox_tenant.test_list_1]\n\n  filter {\n    name = \"name\"\n    value = \"%[1]s_0\"\n  }\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_tenants.test\", \"tenants.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenants.test\", \"tenants.0.name\", \"netbox_tenant.test_list_0\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxTenantsDataSource_tenantgroups(t *testing.T) {\n\ttestSlug := \"tnts_ds_tenant_group_filter\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant_group\" \"group_0\" {\n  name = \"group_%[1]s_1\"\n}\n\nresource \"netbox_tenant\" \"tenant_0\" {\n  name = \"tenant_%[1]s_0\"\n  group_id = netbox_tenant_group.group_0.id\n}\n\ndata \"netbox_tenants\" \"test\" {\n  depends_on = [netbox_tenant.tenant_0, netbox_tenant_group.group_0]\n\n  filter {\n    name = \"name\"\n    value = \"tenant_%[1]s_0\"\n  }\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_tenants.test\", \"tenants.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenants.test\", \"tenants.0.tenant_group.0.name\", \"netbox_tenant_group.group_0\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_tenants.test\", \"tenants.0.tenant_group.0.slug\", \"netbox_tenant_group.group_0\", \"slug\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_virtual_disk.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxVirtualDisk() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxVirtualDiskRead,\n\t\tDescription: `:meta:subcategory:Virtualization:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"name_regex\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringIsValidRegExp,\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"virtual_disks\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"size_mb\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"virtual_machine_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttagsKey: {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem:     &schema.Schema{Type: schema.TypeString},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcustomFieldsKey: {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxVirtualDiskRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := virtualization.NewVirtualizationVirtualDisksListParams()\n\n\t// Get user limit (0 = fetch all)\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.([]interface{})\n\t\tvar tags []string\n\t\tfor _, f := range filterParams {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"name\":\n\t\t\t\tparams.NameIc = &vString\n\t\t\tcase \"tag\":\n\t\t\t\ttags = append(tags, vString)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t\tif len(tags) > 0 {\n\t\t\tparams.Tag = tags\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination (fetch all when name_regex is used)\n\tpaginationHelper := NewPaginationHelper(FetchAll)\n\tvar allDisks []*models.VirtualDisk\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Virtualization.VirtualizationVirtualDisksList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch virtual disks at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallDisks = append(allDisks, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allDisks)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Apply name_regex filter\n\tvar filteredDisks []*models.VirtualDisk\n\tif nameRegex, ok := d.GetOk(\"name_regex\"); ok {\n\t\tr := regexp.MustCompile(nameRegex.(string))\n\t\tfor _, disk := range allDisks {\n\t\t\tif disk.Name != nil && r.MatchString(*disk.Name) {\n\t\t\t\tfilteredDisks = append(filteredDisks, disk)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfilteredDisks = allDisks\n\t}\n\n\t// Apply user limit to filtered results\n\tif userLimit > 0 && int64(len(filteredDisks)) > userLimit {\n\t\tfilteredDisks = filteredDisks[:userLimit]\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredDisks {\n\t\tvar mapping = make(map[string]interface{})\n\t\tif v.ID != 0 {\n\t\t\tmapping[\"id\"] = v.ID\n\t\t}\n\t\tif v.Name != nil {\n\t\t\tmapping[\"name\"] = *v.Name\n\t\t}\n\t\tif v.Description != \"\" {\n\t\t\tmapping[\"description\"] = v.Description\n\t\t}\n\t\tif v.Size != nil {\n\t\t\tmapping[\"size_mb\"] = *v.Size\n\t\t}\n\t\tif v.VirtualMachine != nil {\n\t\t\tmapping[\"virtual_machine_id\"] = v.VirtualMachine.ID\n\t\t}\n\t\tif v.CustomFields != nil {\n\t\t\tmapping[\"custom_fields\"] = flattenCustomFields(v.CustomFields)\n\t\t}\n\t\tif v.Tags != nil {\n\t\t\ttags := []string{}\n\t\t\tfor _, t := range v.Tags {\n\t\t\t\tif t.Name != nil {\n\t\t\t\t\ttags = append(tags, *t.Name)\n\t\t\t\t}\n\t\t\t}\n\t\t\tmapping[\"tags\"] = tags\n\t\t}\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"virtual_disks\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_virtual_disk_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxVirtualDiskDataSource_basic(t *testing.T) {\n\ttestSlug := \"virtual_disk_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresourceName := \"netbox_virtual_disk.test\"\n\tdataSourceName := \"data.netbox_virtual_disk.test\"\n\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"tag_a\" {\n  name = \"%[1]s_a\"\n  color_hex = \"123456\"\n}\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n}\nresource \"netbox_virtual_disk\" \"test\" {\n  name = \"%[1]s\"\n  description = \"description\"\n  size_mb = 30\n  virtual_machine_id = netbox_virtual_machine.test.id\n  tags = [netbox_tag.tag_a.name]\n}\ndata \"netbox_virtual_disk\" \"test\" {\n  filter {\n    name = \"name\"\n    value = netbox_virtual_disk.test.name\n  }\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(dataSourceName, \"virtual_disks.0.id\", resourceName, \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(dataSourceName, \"virtual_disks.0.name\", resourceName, \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(dataSourceName, \"virtual_disks.0.description\", resourceName, \"description\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(dataSourceName, \"virtual_disks.0.size_mb\", resourceName, \"size_mb\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(dataSourceName, \"virtual_disks.0.virtual_machine_id\", resourceName, \"virtual_machine_id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVirtualDiskDataSource_filter_and_list(t *testing.T) {\n\ttestSlug := \"virtual_disk_ds_filter\"\n\ttestName := testAccGetTestName(testSlug)\n\tdataSourceName := \"data.netbox_virtual_disk.filtered\"\n\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"tag_a\" {\n  name = \"%[1]s_a\"\n  color_hex = \"123456\"\n}\nresource \"netbox_tag\" \"tag_b\" {\n  name = \"%[1]s_b\"\n  color_hex = \"654321\"\n}\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n}\nresource \"netbox_virtual_disk\" \"disk_a\" {\n  name = \"%[1]s_disk_a\"\n  description = \"disk a desc\"\n  size_mb = 10\n  virtual_machine_id = netbox_virtual_machine.test.id\n  tags = [netbox_tag.tag_a.name]\n}\nresource \"netbox_virtual_disk\" \"disk_b\" {\n  name = \"%[1]s_disk_b\"\n  description = \"disk b desc\"\n  size_mb = 20\n  virtual_machine_id = netbox_virtual_machine.test.id\n  tags = [netbox_tag.tag_b.name]\n}\ndata \"netbox_virtual_disk\" \"filtered\" {\n  filter {\n    name = \"name\"\n    value = \"%[1]s_disk_a\"\n  }\n  filter {\n    name = \"tag\"\n    value = netbox_tag.tag_a.name\n  }\n  depends_on = [netbox_virtual_disk.disk_a, netbox_virtual_disk.disk_b]\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.0.name\", testName+\"_disk_a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.0.description\", \"disk a desc\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.0.size_mb\", \"10\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"tag_a\" {\n  name = \"%[1]s_a\"\n  color_hex = \"123456\"\n}\nresource \"netbox_tag\" \"tag_b\" {\n  name = \"%[1]s_b\"\n  color_hex = \"654321\"\n}\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n}\nresource \"netbox_virtual_disk\" \"disk_a\" {\n  name = \"%[1]s_disk_a\"\n  description = \"disk a desc\"\n  size_mb = 10\n  virtual_machine_id = netbox_virtual_machine.test.id\n  tags = [netbox_tag.tag_a.name]\n}\nresource \"netbox_virtual_disk\" \"disk_b\" {\n  name = \"%[1]s_disk_b\"\n  description = \"disk b desc\"\n  size_mb = 20\n  virtual_machine_id = netbox_virtual_machine.test.id\n  tags = [netbox_tag.tag_b.name]\n}\ndata \"netbox_virtual_disk\" \"filtered\" {\n  filter {\n    name = \"tag\"\n    value = netbox_tag.tag_b.name\n  }\n  depends_on = [netbox_virtual_disk.disk_a, netbox_virtual_disk.disk_b]\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.0.name\", testName+\"_disk_b\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.0.description\", \"disk b desc\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(dataSourceName, \"virtual_disks.0.size_mb\", \"20\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_virtual_machines.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxVirtualMachine() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxVirtualMachineRead,\n\t\tDescription: `:meta:subcategory:Virtualization:`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"name_regex\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringIsValidRegExp,\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"vms\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"cluster_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"comments\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"config_context\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"custom_fields\": {\n\t\t\t\t\t\t\tType:     schema.TypeMap,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"device_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"device_name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"disk_size_mb\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"local_context_data\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"memory_mb\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"platform_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"platform_slug\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"platform_name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"primary_ip\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"primary_ip4\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"primary_ip6\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tag_ids\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tenant_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vcpus\": {\n\t\t\t\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vm_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxVirtualMachineRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := virtualization.NewVirtualizationVirtualMachinesListParams()\n\n\t// Get user limit (0 = fetch all)\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tvar tags []string\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"cluster_id\":\n\t\t\t\tparams.ClusterID = &vString\n\t\t\tcase \"cluster_group\":\n\t\t\t\tparams.ClusterGroup = &vString\n\t\t\tcase \"device_id\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"device\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"region\":\n\t\t\t\tparams.Region = &vString\n\t\t\tcase \"role\":\n\t\t\t\tparams.Role = &vString\n\t\t\tcase \"site\":\n\t\t\t\tparams.Site = &vString\n\t\t\tcase \"tenant_id\":\n\t\t\t\tparams.TenantID = &vString\n\t\t\tcase \"tag\":\n\t\t\t\ttags = append(tags, vString)\n\t\t\t\tparams.Tag = tags\n\t\t\tcase \"status\":\n\t\t\t\tparams.Status = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination (fetch all when name_regex is used)\n\tpaginationHelper := NewPaginationHelper(FetchAll)\n\tvar allVms []*models.VirtualMachineWithConfigContext\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Virtualization.VirtualizationVirtualMachinesList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch virtual machines at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallVms = append(allVms, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allVms)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Apply name_regex filter\n\tvar filteredVms []*models.VirtualMachineWithConfigContext\n\tif nameRegex, ok := d.GetOk(\"name_regex\"); ok {\n\t\tr := regexp.MustCompile(nameRegex.(string))\n\t\tfor _, vm := range allVms {\n\t\t\tif r.MatchString(*vm.Name) {\n\t\t\t\tfilteredVms = append(filteredVms, vm)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfilteredVms = allVms\n\t}\n\n\t// Apply user limit to filtered results\n\tif userLimit > 0 && int64(len(filteredVms)) > userLimit {\n\t\tfilteredVms = filteredVms[:userLimit]\n\t}\n\n\tif len(filteredVms) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredVms {\n\t\tvar mapping = make(map[string]interface{})\n\t\tif v.Cluster != nil {\n\t\t\tmapping[\"cluster_id\"] = v.Cluster.ID\n\t\t}\n\t\tif v.Comments != \"\" {\n\t\t\tmapping[\"comments\"] = v.Comments\n\t\t}\n\t\tif v.Description != \"\" {\n\t\t\tmapping[\"description\"] = v.Description\n\t\t}\n\t\tif v.Device != nil {\n\t\t\tmapping[\"device_id\"] = v.Device.ID\n\t\t\tmapping[\"device_name\"] = v.Device.Name\n\t\t}\n\t\tif v.ConfigContext != nil {\n\t\t\tif configContext, err := json.Marshal(v.ConfigContext); err == nil {\n\t\t\t\tmapping[\"config_context\"] = string(configContext)\n\t\t\t}\n\t\t}\n\t\tif v.CustomFields != nil {\n\t\t\tmapping[\"custom_fields\"] = flattenCustomFields(v.CustomFields)\n\t\t}\n\t\tif v.Disk != nil {\n\t\t\tmapping[\"disk_size_mb\"] = *v.Disk\n\t\t}\n\t\tif v.LocalContextData != nil {\n\t\t\tif localContextData, err := json.Marshal(v.LocalContextData); err == nil {\n\t\t\t\tmapping[\"local_context_data\"] = string(localContextData)\n\t\t\t}\n\t\t}\n\t\tif v.Memory != nil {\n\t\t\tmapping[\"memory_mb\"] = *v.Memory\n\t\t}\n\t\tif v.Name != nil {\n\t\t\tmapping[\"name\"] = *v.Name\n\t\t}\n\t\tif v.Platform != nil {\n\t\t\tmapping[\"platform_id\"] = v.Platform.ID\n\t\t\tmapping[\"platform_slug\"] = v.Platform.Slug\n\t\t\tmapping[\"platform_name\"] = v.Platform.Name\n\t\t}\n\t\tif v.PrimaryIP != nil {\n\t\t\tmapping[\"primary_ip\"] = v.PrimaryIP.Address\n\t\t}\n\t\tif v.PrimaryIp4 != nil {\n\t\t\tmapping[\"primary_ip4\"] = v.PrimaryIp4.Address\n\t\t}\n\t\tif v.PrimaryIp6 != nil {\n\t\t\tmapping[\"primary_ip6\"] = v.PrimaryIp6.Address\n\t\t}\n\t\tif v.Role != nil {\n\t\t\tmapping[\"role_id\"] = v.Role.ID\n\t\t}\n\t\tif v.Site != nil {\n\t\t\tmapping[\"site_id\"] = v.Site.ID\n\t\t}\n\t\tif v.Status != nil {\n\t\t\tmapping[\"status\"] = v.Status.Value\n\t\t}\n\t\tif v.Tags != nil {\n\t\t\tvar tags []int64\n\t\t\tfor _, t := range v.Tags {\n\t\t\t\ttags = append(tags, t.ID)\n\t\t\t}\n\t\t\tmapping[\"tag_ids\"] = tags\n\t\t}\n\t\tif v.Tenant != nil {\n\t\t\tmapping[\"tenant_id\"] = v.Tenant.ID\n\t\t}\n\t\tif v.Vcpus != nil {\n\t\t\tmapping[\"vcpus\"] = *v.Vcpus\n\t\t}\n\n\t\tmapping[\"vm_id\"] = v.ID\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"vms\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_virtual_machines_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxVirtualMachinesDataSource_basic(t *testing.T) {\n\ttestSlug := \"vm_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tdependencies := testAccNetboxVirtualMachineDataSourceDependencies(testName)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxVirtualMachineDataSourceFilterName(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.0.name\", testName+\"_0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.0.vcpus\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.0.memory_mb\", \"1024\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.0.disk_size_mb\", \"256\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.0.comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.platform_slug\", \"netbox_platform.test\", \"slug\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.platform_name\", \"netbox_platform.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.device_name\", \"netbox_device.test\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxVirtualMachineDataSourceFilterCluster,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.#\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.name\", \"netbox_virtual_machine.test0\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.1.name\", \"netbox_virtual_machine.test1\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.2.name\", \"netbox_virtual_machine.test2\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.3.name\", \"netbox_virtual_machine.test3\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxVirtualMachineDataSourceFilterTenantID,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.name\", \"netbox_virtual_machine.test0\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxVirtualMachineDataSourceNameRegex,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.name\", \"netbox_virtual_machine.test2\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.1.name\", \"netbox_virtual_machine.test3\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxVirtualMachineDataSourceLimit,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test\", \"vms.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test\", \"vms.0.cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVirtualMachinesDataSource_tags(t *testing.T) {\n\ttestSlug := \"vm_ds_tags\"\n\ttestName := testAccGetTestName(testSlug)\n\tdependencies := testAccNetboxVirtualMachineDataSourceDependenciesWithTags(testName)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxVirtualMachineDataSourceTagA(testName) + testAccNetboxVirtualMachineDataSourceTagB(testName) + testAccNetboxVirtualMachineDataSourceTagAB(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.tag-a\", \"vms.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.tag-b\", \"vms.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.tag-ab\", \"vms.#\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVirtualMachinesDataSource_status(t *testing.T) {\n\ttestSlug := \"vm_ds_status\"\n\ttestName := testAccGetTestName(testSlug)\n\tdependencies := testAccNetboxVirtualMachineDataSourceDependenciesWithStatus(testName)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: dependencies,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: dependencies + testAccNetboxVirtualMachineDataSourceStatusActive + testAccNetboxVirtualMachineDataSourceStatusDecommissioning,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test_active\", \"vms.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_virtual_machines.test_decommissioning\", \"vms.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test_active\", \"vms.0.status\", \"netbox_virtual_machine.test0\", \"status\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_virtual_machines.test_decommissioning\", \"vms.0.status\", \"netbox_virtual_machine.test1\", \"status\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxVirtualMachineDataSourceDependencies(testName string) string {\n\treturn testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test0\" {\n  name = \"%[1]s_0\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  device_id = netbox_device.test.id\n  comments = \"thisisacomment\"\n  memory_mb = 1024\n  disk_size_mb = 256\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  platform_id = netbox_platform.test.id\n  vcpus = 4\n}\n\nresource \"netbox_virtual_machine\" \"test1\" {\n  name = \"%[1]s_1\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_virtual_machine\" \"test2\" {\n  name = \"%[1]s_2_regex\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_virtual_machine\" \"test3\" {\n  name = \"%[1]s_3_regex\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n}\n`, testName)\n}\n\nfunc testAccNetboxVirtualMachineDataSourceDependenciesWithTags(testName string) string {\n\treturn testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_tag\" \"servicea\" {\n  name = \"%[1]s_service-a\"\n}\n\nresource \"netbox_tag\" \"serviceb\" {\n  name = \"%[1]s_service-b\"\n}\n\nresource \"netbox_virtual_machine\" \"test0\" {\n  name = \"%[1]s_0\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  comments = \"thisisacomment\"\n  memory_mb = 1024\n  disk_size_mb = 256\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  platform_id = netbox_platform.test.id\n  vcpus = 4\n  tags = [\n    netbox_tag.servicea.name,\n    netbox_tag.serviceb.name,\n  ]\n}\n\nresource \"netbox_virtual_machine\" \"test1\" {\n  name = \"%[1]s_1\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  tags = [\n    netbox_tag.servicea.name,\n  ]\n}\n\nresource \"netbox_virtual_machine\" \"test2\" {\n  name = \"%[1]s_2_regex\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  tags = [\n    netbox_tag.serviceb.name,\n  ]\n}\n`, testName)\n}\n\nconst testAccNetboxVirtualMachineDataSourceFilterCluster = `\ndata \"netbox_virtual_machines\" \"test\" {\n  filter {\n    name  = \"cluster_id\"\n    value = netbox_cluster.test.id\n  }\n}`\n\nconst testAccNetboxVirtualMachineDataSourceFilterTenantID = `\ndata \"netbox_virtual_machines\" \"test\" {\n  filter {\n    name  = \"tenant_id\"\n    value = netbox_tenant.test.id\n  }\n}`\n\nfunc testAccNetboxVirtualMachineDataSourceFilterName(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_virtual_machines\" \"test\" {\n  filter {\n    name  = \"name\"\n    value = \"%[1]s_0\"\n  }\n}`, testName)\n}\n\nconst testAccNetboxVirtualMachineDataSourceNameRegex = `\ndata \"netbox_virtual_machines\" \"test\" {\n  name_regex = \"test.*_regex\"\n}`\n\nconst testAccNetboxVirtualMachineDataSourceLimit = `\ndata \"netbox_virtual_machines\" \"test\" {\n  limit = 1\n  filter {\n    name  = \"cluster_id\"\n    value = netbox_cluster.test.id\n  }\n}`\n\nfunc testAccNetboxVirtualMachineDataSourceTagA(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_virtual_machines\" \"tag-a\" {\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s_service-a\"\n  }\n}`, testName)\n}\n\nfunc testAccNetboxVirtualMachineDataSourceTagB(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_virtual_machines\" \"tag-b\" {\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s_service-b\"\n  }\n}`, testName)\n}\n\nfunc testAccNetboxVirtualMachineDataSourceTagAB(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_virtual_machines\" \"tag-ab\" {\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s_service-a\"\n  }\n  filter {\n    name  = \"tag\"\n    value = \"%[1]s_service-b\"\n  }\n}`, testName)\n}\n\nconst testAccNetboxVirtualMachineDataSourceStatusActive = `\ndata \"netbox_virtual_machines\" \"test_active\" {\n  filter {\n    name  = \"status\"\n    value = \"active\"\n  }\n}`\n\nconst testAccNetboxVirtualMachineDataSourceStatusDecommissioning = `\ndata \"netbox_virtual_machines\" \"test_decommissioning\" {\n  filter {\n    name  = \"status\"\n    value = \"decommissioning\"\n  }\n}`\n\nfunc testAccNetboxVirtualMachineDataSourceDependenciesWithStatus(testName string) string {\n\treturn testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_tag\" \"servicea\" {\n  name = \"%[1]s_service-a\"\n}\n\nresource \"netbox_virtual_machine\" \"test0\" {\n  name         = \"%[1]s_0\"\n  cluster_id   = netbox_cluster.test.id\n  site_id      = netbox_site.test.id\n  comments     = \"thisisacomment\"\n  memory_mb    = 1024\n  disk_size_mb = 256\n  tenant_id    = netbox_tenant.test.id\n  role_id      = netbox_device_role.test.id\n  platform_id  = netbox_platform.test.id\n  vcpus        = 4\n  status       = \"active\"\n  tags         = [\n    netbox_tag.servicea.name,\n  ]\n}\n\nresource \"netbox_virtual_machine\" \"test1\" {\n  name         = \"%[1]s_1\"\n  cluster_id   = netbox_cluster.test.id\n  site_id      = netbox_site.test.id\n  comments     = \"thisisacomment\"\n  memory_mb    = 1024\n  disk_size_mb = 256\n  tenant_id    = netbox_tenant.test.id\n  role_id      = netbox_device_role.test.id\n  platform_id  = netbox_platform.test.id\n  vcpus        = 4\n  status       = \"decommissioning\"\n  tags         = [\n    netbox_tag.servicea.name,\n  ]\n}`, testName)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vlan.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxVlan() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxVlanRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"vid\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.IntBetween(1, 4094),\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"site\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"tenant\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxVlanRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := ipam.NewIpamVlansListParams()\n\n\tparams.Limit = int64ToPtr(2)\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.Name = &name\n\t}\n\tif vid, ok := d.Get(\"vid\").(int); ok && vid != 0 {\n\t\tparams.Vid = strToPtr(strconv.Itoa(vid))\n\t}\n\tif groupID, ok := d.Get(\"group_id\").(int); ok && groupID != 0 {\n\t\tparams.GroupID = strToPtr(strconv.Itoa(groupID))\n\t}\n\tif roleID, ok := d.Get(\"role\").(int); ok && roleID != 0 {\n\t\tparams.RoleID = strToPtr(strconv.Itoa(roleID))\n\t}\n\tif tenantID, ok := d.Get(\"tenant\").(int); ok && tenantID != 0 {\n\t\tparams.TenantID = strToPtr(strconv.Itoa(tenantID))\n\t}\n\n\tres, err := api.Ipam.IpamVlansList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one vlan returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no vlan found matching filter\")\n\t}\n\n\tvlan := res.GetPayload().Results[0]\n\n\td.SetId(strconv.FormatInt(vlan.ID, 10))\n\td.Set(\"vid\", vlan.Vid)\n\td.Set(\"name\", vlan.Name)\n\td.Set(\"status\", vlan.Status.Value)\n\td.Set(\"description\", vlan.Description)\n\n\tif vlan.Group != nil {\n\t\td.Set(\"group_id\", vlan.Group.ID)\n\t}\n\tif vlan.Role != nil {\n\t\td.Set(\"role\", vlan.Role.ID)\n\t}\n\tif vlan.Site != nil {\n\t\td.Set(\"site\", vlan.Site.ID)\n\t}\n\tif vlan.Tenant != nil {\n\t\td.Set(\"tenant\", vlan.Tenant.ID)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vlan_group.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxVlanGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxVlanGroupRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"id\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tComputed:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"id\", \"name\", \"slug\", \"scope_type\"},\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tComputed:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"id\", \"name\", \"slug\", \"scope_type\"},\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tAtLeastOneOf: []string{\"id\", \"name\", \"slug\", \"scope_type\"},\n\t\t\t},\n\t\t\t\"scope_type\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxVlanGroupScopeTypeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxVlanGroupScopeTypeOptions),\n\t\t\t\tAtLeastOneOf: []string{\"id\", \"name\", \"slug\", \"scope_type\"},\n\t\t\t},\n\t\t\t\"scope_id\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"scope_type\"},\n\t\t\t},\n\t\t\t\"vlan_count\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxVlanGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tparams := ipam.NewIpamVlanGroupsListParams()\n\n\tparams.Limit = int64ToPtr(2)\n\n\tif id, ok := d.Get(\"id\").(string); ok && id != \"\" {\n\t\tparams.ID = strToPtr(id)\n\t}\n\tif name, ok := d.Get(\"name\").(string); ok && name != \"\" {\n\t\tparams.Name = strToPtr(name)\n\t}\n\tif slug, ok := d.Get(\"slug\").(string); ok && slug != \"\" {\n\t\tparams.Slug = strToPtr(slug)\n\t}\n\tif scopeType, ok := d.Get(\"scope_type\").(string); ok && scopeType != \"\" {\n\t\tparams.ScopeType = strToPtr(scopeType)\n\t}\n\tif scopeID, ok := d.Get(\"scope_id\").(string); ok && scopeID != \"\" {\n\t\tparams.ScopeID = strToPtr(scopeID)\n\t}\n\n\tres, err := api.Ipam.IpamVlanGroupsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one vlan group returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no vlan group found matching filter\")\n\t}\n\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"id\", strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\td.Set(\"vlan_count\", result.VlanCount)\n\td.Set(\"description\", result.Description)\n\tif result.ScopeID != nil {\n\t\td.Set(\"scope_id\", strconv.FormatInt(*result.ScopeID, 10))\n\t}\n\tif result.ScopeType != nil {\n\t\td.Set(\"scope_type\", *result.ScopeType)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vlan_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxVlanGroupDataSource_basic(t *testing.T) {\n\ttestSlug := \"test_group\"\n\tanotherSlug := \"not_test_group\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxVlanGroupSetUp(testSlug, testName)\n\textendedSetUp := testAccNetboxVlanGroupSetUpMore(testSlug, anotherSlug, testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + testAccNetboxVlanGroupDataNoResult,\n\t\t\t\tExpectError: regexp.MustCompile(\"no vlan group found matching filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanGroupDataByID(\"netbox_vlan_group.test\", \"id\"),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_group.test\", \"id\", \"netbox_vlan_group.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanGroupDataByName(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_group.test\", \"id\", \"netbox_vlan_group.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanGroupDataBySlug(testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_group.test\", \"id\", \"netbox_vlan_group.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + extendedSetUp + testAccNetboxVlanGroupDataByNameAndScope(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_group.test\", \"id\", \"netbox_vlan_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_group.test\", \"slug\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_group.test\", \"description\", \"Test\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_group.test\", \"scope_type\", \"dcim.site\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_group.test\", \"scope_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + extendedSetUp + testAccNetboxVlanGroupDataBySlugAndScope(testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_group.test\", \"id\", \"netbox_vlan_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_group.test\", \"slug\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_group.test\", \"description\", \"Test\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_group.test\", \"scope_type\", \"dcim.site\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_group.test\", \"scope_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + extendedSetUp + testAccNetboxVlanGroupDataByName(testName),\n\t\t\t\tExpectError: regexp.MustCompile(\"more than one vlan group returned, specify a more narrow filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + extendedSetUp + testAccNetboxVlanGroupDataBySlug(testSlug),\n\t\t\t\tExpectError: regexp.MustCompile(\"more than one vlan group returned, specify a more narrow filter\"),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxVlanGroupSetUp(testSlug, testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[2]s\"\n}\n\nresource \"netbox_vlan_group\" \"test\" {\n  slug        = \"%[1]s\"\n  name        = \"%[2]s\"\n  description = \"Test\"\n  scope_type  = \"dcim.site\"\n  scope_id    = netbox_site.test.id\n  vid_ranges  = [[1, 4094]]\n  tags        = []\n}\n`, testSlug, testName)\n}\n\nfunc testAccNetboxVlanGroupSetUpMore(testSlug, anotherSlug, testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_vlan_group\" \"same_name\" {\n  slug        = \"%[1]s\"\n  name        = \"%[3]s\"\n  vid_ranges  = [[1, 4094]]\n}\n\nresource \"netbox_vlan_group\" \"not_same\" {\n  slug        = \"%[2]s\"\n  name        = \"%[3]s_unique\"\n  vid_ranges  = [[1, 4094]]\n}\n`, testSlug, anotherSlug, testName)\n}\n\nconst testAccNetboxVlanGroupDataNoResult = `\ndata \"netbox_vlan_group\" \"no_result\" {\n  name = \"_no_result_\"\n}`\n\nfunc testAccNetboxVlanGroupDataByID(resourceRef, field string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan_group\" \"test\" {\n  id = %[1]s.%[2]s\n}`, resourceRef, field)\n}\n\nfunc testAccNetboxVlanGroupDataByName(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan_group\" \"test\" {\n  name = \"%[1]s\"\n}`, testName)\n}\n\nfunc testAccNetboxVlanGroupDataBySlug(testSlug string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan_group\" \"test\" {\n  slug = \"%[1]s\"\n}`, testSlug)\n}\n\nfunc testAccNetboxVlanGroupDataByNameAndScope(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan_group\" \"test\" {\n  name       = \"%[1]s\"\n  scope_type = \"dcim.site\"\n  scope_id   = netbox_site.test.id\n}`, testName)\n}\n\nfunc testAccNetboxVlanGroupDataBySlugAndScope(testSlug string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan_group\" \"test\" {\n  slug       = \"%[1]s\"\n  scope_type = \"dcim.site\"\n  scope_id   = netbox_site.test.id\n}`, testSlug)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vlan_groups.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxVlanGroups() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxVlanGroupsRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"vlan_groups\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"slug\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"ranges\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\t\t\t\"start\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"end\": {\n\t\t\t\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"used\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tag_ids\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxVlanGroupsRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamVlanGroupsListParams()\n\n\t// Get user limit (0 = fetch all)\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tvar tags []string\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = strToPtr(vString)\n\t\t\tcase \"name__empty\":\n\t\t\t\tparams.NameEmpty = strToPtr(vString)\n\t\t\tcase \"name__ic\":\n\t\t\t\tparams.NameIc = strToPtr(vString)\n\t\t\tcase \"name__ie\":\n\t\t\t\tparams.NameIe = strToPtr(vString)\n\t\t\tcase \"name__iew\":\n\t\t\t\tparams.NameIew = strToPtr(vString)\n\t\t\tcase \"name__isw\":\n\t\t\t\tparams.NameIsw = strToPtr(vString)\n\t\t\tcase \"name__n\":\n\t\t\t\tparams.Namen = strToPtr(vString)\n\t\t\tcase \"name__nic\":\n\t\t\t\tparams.NameNic = strToPtr(vString)\n\t\t\tcase \"name__nie\":\n\t\t\t\tparams.NameNie = strToPtr(vString)\n\t\t\tcase \"name__niew\":\n\t\t\t\tparams.NameNiew = strToPtr(vString)\n\t\t\tcase \"name__nisw\":\n\t\t\t\tparams.NameNisw = strToPtr(vString)\n\t\t\tcase \"slug\":\n\t\t\t\tparams.Slug = strToPtr(vString)\n\t\t\tcase \"slug__empty\":\n\t\t\t\tparams.SlugEmpty = strToPtr(vString)\n\t\t\tcase \"slug__ic\":\n\t\t\t\tparams.SlugIc = strToPtr(vString)\n\t\t\tcase \"slug__ie\":\n\t\t\t\tparams.SlugIe = strToPtr(vString)\n\t\t\tcase \"slug__iew\":\n\t\t\t\tparams.SlugIew = strToPtr(vString)\n\t\t\tcase \"slug__isw\":\n\t\t\t\tparams.SlugIsw = strToPtr(vString)\n\t\t\tcase \"slug__n\":\n\t\t\t\tparams.Slugn = strToPtr(vString)\n\t\t\tcase \"slug__nic\":\n\t\t\t\tparams.SlugNic = strToPtr(vString)\n\t\t\tcase \"slug__nie\":\n\t\t\t\tparams.SlugNie = strToPtr(vString)\n\t\t\tcase \"slug__niew\":\n\t\t\t\tparams.SlugNiew = strToPtr(vString)\n\t\t\tcase \"slug__nisw\":\n\t\t\t\tparams.SlugNisw = strToPtr(vString)\n\t\t\tcase \"description\":\n\t\t\t\tparams.Description = strToPtr(vString)\n\t\t\tcase \"description__empty\":\n\t\t\t\tparams.DescriptionEmpty = strToPtr(vString)\n\t\t\tcase \"description__ic\":\n\t\t\t\tparams.DescriptionIc = strToPtr(vString)\n\t\t\tcase \"description__ie\":\n\t\t\t\tparams.DescriptionIe = strToPtr(vString)\n\t\t\tcase \"description__iew\":\n\t\t\t\tparams.DescriptionIew = strToPtr(vString)\n\t\t\tcase \"description__isw\":\n\t\t\t\tparams.DescriptionIsw = strToPtr(vString)\n\t\t\tcase \"description__n\":\n\t\t\t\tparams.Descriptionn = strToPtr(vString)\n\t\t\tcase \"description__nic\":\n\t\t\t\tparams.DescriptionNic = strToPtr(vString)\n\t\t\tcase \"description__nie\":\n\t\t\t\tparams.DescriptionNie = strToPtr(vString)\n\t\t\tcase \"description__niew\":\n\t\t\t\tparams.DescriptionNiew = strToPtr(vString)\n\t\t\tcase \"description__nisw\":\n\t\t\t\tparams.DescriptionNisw = strToPtr(vString)\n\t\t\tcase \"id\":\n\t\t\t\tparams.ID = strToPtr(vString)\n\t\t\tcase \"id__gt\":\n\t\t\t\tparams.IDGt = strToPtr(vString)\n\t\t\tcase \"id__gte\":\n\t\t\t\tparams.IDGte = strToPtr(vString)\n\t\t\tcase \"id__lt\":\n\t\t\t\tparams.IDLt = strToPtr(vString)\n\t\t\tcase \"id__lte\":\n\t\t\t\tparams.IDLte = strToPtr(vString)\n\t\t\tcase \"id__n\":\n\t\t\t\tparams.IDn = strToPtr(vString)\n\t\t\tcase \"scope_type\":\n\t\t\t\tparams.ScopeType = strToPtr(vString)\n\t\t\tcase \"scope_type__n\":\n\t\t\t\tparams.ScopeTypen = strToPtr(vString)\n\t\t\tcase \"scope_id\":\n\t\t\t\tparams.ScopeID = strToPtr(vString)\n\t\t\tcase \"scope_id__gt\":\n\t\t\t\tparams.ScopeIDGt = strToPtr(vString)\n\t\t\tcase \"scope_id__gte\":\n\t\t\t\tparams.ScopeIDGte = strToPtr(vString)\n\t\t\tcase \"scope_id__lt\":\n\t\t\t\tparams.ScopeIDLt = strToPtr(vString)\n\t\t\tcase \"scope_id__lte\":\n\t\t\t\tparams.ScopeIDLte = strToPtr(vString)\n\t\t\tcase \"scope_id__n\":\n\t\t\t\tparams.ScopeIDn = strToPtr(vString)\n\t\t\tcase \"site_id\", \"site\":\n\t\t\t\tif f, err := strconv.ParseFloat(vString, 64); err == nil {\n\t\t\t\t\tparams.Site = float64ToPtr(f)\n\t\t\t\t}\n\t\t\tcase \"location_id\", \"location\":\n\t\t\t\tif f, err := strconv.ParseFloat(vString, 64); err == nil {\n\t\t\t\t\tparams.Location = float64ToPtr(f)\n\t\t\t\t}\n\t\t\tcase \"rack_id\", \"rack\":\n\t\t\t\tif f, err := strconv.ParseFloat(vString, 64); err == nil {\n\t\t\t\t\tparams.Rack = float64ToPtr(f)\n\t\t\t\t}\n\t\t\tcase \"region_id\", \"region\":\n\t\t\t\tif f, err := strconv.ParseFloat(vString, 64); err == nil {\n\t\t\t\t\tparams.Region = float64ToPtr(f)\n\t\t\t\t}\n\t\t\tcase \"sitegroup_id\", \"sitegroup\":\n\t\t\t\tif f, err := strconv.ParseFloat(vString, 64); err == nil {\n\t\t\t\t\tparams.Sitegroup = float64ToPtr(f)\n\t\t\t\t}\n\t\t\tcase \"cluster_id\", \"cluster\":\n\t\t\t\tif f, err := strconv.ParseFloat(vString, 64); err == nil {\n\t\t\t\t\tparams.Cluster = float64ToPtr(f)\n\t\t\t\t}\n\t\t\tcase \"clustergroup_id\", \"clustergroup\":\n\t\t\t\tif f, err := strconv.ParseFloat(vString, 64); err == nil {\n\t\t\t\t\tparams.Clustergroup = float64ToPtr(f)\n\t\t\t\t}\n\t\t\tcase \"minvid\":\n\t\t\t\tparams.MinVid = strToPtr(vString)\n\t\t\tcase \"minvid__gt\":\n\t\t\t\tparams.MinVidGt = strToPtr(vString)\n\t\t\tcase \"minvid__gte\":\n\t\t\t\tparams.MinVidGte = strToPtr(vString)\n\t\t\tcase \"minvid__lt\":\n\t\t\t\tparams.MinVidLt = strToPtr(vString)\n\t\t\tcase \"minvid__lte\":\n\t\t\t\tparams.MinVidLte = strToPtr(vString)\n\t\t\tcase \"minvid__n\":\n\t\t\t\tparams.MinVidn = strToPtr(vString)\n\t\t\tcase \"maxvid\":\n\t\t\t\tparams.MaxVid = strToPtr(vString)\n\t\t\tcase \"maxvid__gt\":\n\t\t\t\tparams.MaxVidGt = strToPtr(vString)\n\t\t\tcase \"maxvid__gte\":\n\t\t\t\tparams.MaxVidGte = strToPtr(vString)\n\t\t\tcase \"maxvid__lt\":\n\t\t\t\tparams.MaxVidLt = strToPtr(vString)\n\t\t\tcase \"maxvid__lte\":\n\t\t\t\tparams.MaxVidLte = strToPtr(vString)\n\t\t\tcase \"maxvid__n\":\n\t\t\t\tparams.MaxVidn = strToPtr(vString)\n\t\t\tcase \"tag\":\n\t\t\t\ttags = append(tags, vString)\n\t\t\t\tparams.Tag = tags\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allVlanGroups []*models.VLANGroup\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Ipam.IpamVlanGroupsList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch VLAN groups at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallVlanGroups = append(allVlanGroups, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allVlanGroups)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allVlanGroups))\n\tfilteredVlanGroups := allVlanGroups[:trimmedCount]\n\n\tif len(filteredVlanGroups) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, vg := range filteredVlanGroups {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = vg.ID\n\t\tmapping[\"name\"] = vg.Name\n\t\tmapping[\"slug\"] = vg.Slug\n\t\tmapping[\"description\"] = vg.Description\n\n\t\tmapping[\"ranges\"] = []map[string]int64{}\n\t\tfor _, v := range vg.VidRanges {\n\t\t\tmapping[\"ranges\"] = append(mapping[\"ranges\"].([]map[string]int64), map[string]int64{\n\t\t\t\t\"start\": v[0],\n\t\t\t\t\"end\":   v[1],\n\t\t\t})\n\t\t}\n\t\tmapping[\"used\"] = vg.VlanCount\n\n\t\tif vg.Tags != nil {\n\t\t\tvar tagIDs []int64\n\t\t\tfor _, t := range vg.Tags {\n\t\t\t\ttagIDs = append(tagIDs, t.ID)\n\t\t\t}\n\t\t\tmapping[\"tag_ids\"] = tagIDs\n\t\t}\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"vlan_groups\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vlan_groups_test.go",
    "content": "package netbox\n\nimport (\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxVlanGroupsSetUp() string {\n\treturn `\nresource \"netbox_vlan_group\" \"test_1\" {\n  name \t\t\t = \"VLANGroup1\"\n  slug \t\t\t = \"vlangroup1\"\n  vid_ranges = [[100, 200]]\n}\n\nresource \"netbox_vlan_group\" \"test_2\" {\n  name \t\t\t = \"VLANGroup2\"\n  slug \t\t\t = \"vlangroup2\"\n  vid_ranges = [[300, 400]]\n}\n\nresource \"netbox_vlan_group\" \"test_3\" {\n  name \t\t\t = \"VLANGroup3\"\n  slug \t\t\t = \"vlangroup3\"\n  vid_ranges = [[500, 600]]\n}`\n}\n\nfunc testAccNetboxVlanGroupsByName() string {\n\treturn `\ndata \"netbox_vlan_groups\" \"test\" {\n  filter {\n\tname  = \"name\"\n\tvalue = \"VLANGroup1\"\n  }\n}`\n}\n\nfunc testAccNetboxVlanGroupsBySlug() string {\n\treturn `\ndata \"netbox_vlan_groups\" \"test\" {\n  filter {\n\tname = \"slug\"\n\tvalue = \"vlangroup2\"\n  }\n}`\n}\n\nfunc testAccNetboxVlanGroupsWithNameIsw() string {\n\treturn `\ndata \"netbox_vlan_groups\" \"test\" {\n  filter {\n\tname  = \"name__isw\"\n\tvalue = \"VLANGroup\"\n  }\n}`\n}\n\nfunc testAccNetboxVlanGroupsByID() string {\n\treturn `\ndata \"netbox_vlan_groups\" \"test\" {\n  filter {\n\tname  = \"id\"\n\tvalue = netbox_vlan_group.test_1.id\n  }\n}`\n}\n\nfunc testAccNetboxVlanGroupsWithLimit() string {\n\treturn `\ndata \"netbox_vlan_groups\" \"test\" {\n  filter {\n\tname  = \"name__isw\"\n\tvalue = \"VLANGroup\"\n  }\n  limit = 2\n}`\n}\n\nfunc TestAccNetboxVlanGroupsDataSource_basic(t *testing.T) {\n\tsetUp := testAccNetboxVlanGroupsSetUp()\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_1\", \"name\", \"VLANGroup1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_1\", \"slug\", \"vlangroup1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanGroupsByName(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_groups.test\", \"vlan_groups.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_groups.test\", \"vlan_groups.0.name\", \"netbox_vlan_group.test_1\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_groups.test\", \"vlan_groups.0.slug\", \"netbox_vlan_group.test_1\", \"slug\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanGroupsBySlug(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_groups.test\", \"vlan_groups.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_groups.test\", \"vlan_groups.0.slug\", \"netbox_vlan_group.test_2\", \"slug\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVlanGroupsDataSource_search(t *testing.T) {\n\tsetUp := testAccNetboxVlanGroupsSetUp()\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_1\", \"name\", \"VLANGroup1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanGroupsWithNameIsw(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_groups.test\", \"vlan_groups.#\", \"3\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_groups.test\", \"vlan_groups.0.slug\", \"netbox_vlan_group.test_1\", \"slug\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_groups.test\", \"vlan_groups.1.slug\", \"netbox_vlan_group.test_2\", \"slug\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_groups.test\", \"vlan_groups.2.slug\", \"netbox_vlan_group.test_3\", \"slug\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVlanGroupsDataSource_byID(t *testing.T) {\n\tsetUp := testAccNetboxVlanGroupsSetUp()\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanGroupsByID(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_groups.test\", \"vlan_groups.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan_groups.test\", \"vlan_groups.0.name\", \"netbox_vlan_group.test_1\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVlanGroupsDataSource_limit(t *testing.T) {\n\tsetUp := testAccNetboxVlanGroupsSetUp()\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanGroupsWithLimit(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan_groups.test\", \"vlan_groups.#\", \"2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vlan_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxVlanDataSource_basic(t *testing.T) {\n\ttestVid := 4092\n\ttestName := testAccGetTestName(\"vlan\")\n\tsetUp := testAccNetboxVlanSetUp(testVid, testName)\n\textendedSetUp := testAccNetboxVlanSetUpMore(testVid, testVid-1, testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + testAccNetboxVlanDataNoResult,\n\t\t\t\tExpectError: regexp.MustCompile(\"no vlan found matching filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanDataByName(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan.test\", \"id\", \"netbox_vlan.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlanDataByVid(testVid),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan.test\", \"id\", \"netbox_vlan.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tConfig: setUp + extendedSetUp + testAccNetboxVlanDataByNameAndRole(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan.test\", \"id\", \"netbox_vlan.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + extendedSetUp + testAccNetboxVlanDataByVidAndTenant(testVid),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan.test\", \"id\", \"netbox_vlan.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlan.test\", \"description\", \"Test\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan.test\", \"role\", \"netbox_ipam_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan.test\", \"site\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlan.test\", \"tenant\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + extendedSetUp + testAccNetboxVlanDataByName(testName),\n\t\t\t\tExpectError: regexp.MustCompile(\"more than one vlan returned, specify a more narrow filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      setUp + extendedSetUp + testAccNetboxVlanDataByVid(testVid),\n\t\t\t\tExpectError: regexp.MustCompile(\"more than one vlan returned, specify a more narrow filter\"),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxVlanSetUp(testVid int, testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_ipam_role\" \"test\" {\n\tname = \"%[2]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n\tname = \"%[2]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n\tname = \"%[2]s\"\n}\n\nresource \"netbox_vlan\" \"test\" {\n\tvid         = %[1]d\n\tname        = \"%[2]s\"\n\tdescription = \"Test\"\n\trole_id     = netbox_ipam_role.test.id\n\tsite_id     = netbox_site.test.id\n\tstatus      = \"active\"\n\ttags        = []\n\ttenant_id   = netbox_tenant.test.id\n}\n`, testVid, testName)\n}\n\nfunc testAccNetboxVlanSetUpMore(testVid int, anotherVid int, testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_vlan\" \"same_name\" {\n\tvid  = %[1]d\n\tname = \"%[3]s\"\n}\n\nresource \"netbox_vlan\" \"not_same\" {\n\tvid  = %[2]d\n\tname = \"%[3]s_unique\"\n}\n`, testVid, anotherVid, testName)\n}\n\nconst testAccNetboxVlanDataNoResult = `\ndata \"netbox_vlan\" \"no_result\" {\n\tname = \"_no_result_\"\n}`\n\nfunc testAccNetboxVlanDataByName(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan\" \"test\" {\n\tname = \"%[1]s\"\n}`, testName)\n}\n\nfunc testAccNetboxVlanDataByVid(testVid int) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan\" \"test\" {\n\tvid = \"%[1]d\"\n}`, testVid)\n}\n\nfunc testAccNetboxVlanDataByNameAndRole(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan\" \"test\" {\n\tname = \"%[1]s\"\n\trole = netbox_ipam_role.test.id\n}`, testName)\n}\n\nfunc testAccNetboxVlanDataByVidAndTenant(testVid int) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vlan\" \"test\" {\n\tvid    = \"%[1]d\"\n\ttenant = netbox_tenant.test.id\n}`, testVid)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vlans.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxVlans() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxVlansRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"vlans\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"vid\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"group_id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"site\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tag_ids\": {\n\t\t\t\t\t\t\tType:     schema.TypeList,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tenant\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxVlansRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamVlansListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tvar tags []string\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"vid\":\n\t\t\t\tparams.Vid = &vString\n\t\t\tcase \"vid__gt\":\n\t\t\t\tparams.VidGt = &vString\n\t\t\tcase \"vid__gte\":\n\t\t\t\tparams.VidGte = &vString\n\t\t\tcase \"vid__lt\":\n\t\t\t\tparams.VidLt = &vString\n\t\t\tcase \"vid__lte\":\n\t\t\t\tparams.VidLte = &vString\n\t\t\tcase \"vid__n\":\n\t\t\t\tparams.Vidn = &vString\n\t\t\tcase \"group\":\n\t\t\t\tparams.Group = &vString\n\t\t\tcase \"group__n\":\n\t\t\t\tparams.Groupn = &vString\n\t\t\tcase \"group_id\":\n\t\t\t\tparams.GroupID = &vString\n\t\t\tcase \"group_id__n\":\n\t\t\t\tparams.GroupIDn = &vString\n\t\t\tcase \"tag\":\n\t\t\t\ttags = append(tags, vString)\n\t\t\t\tparams.Tag = tags\n\t\t\tcase \"tenant\":\n\t\t\t\tparams.Tenant = &vString\n\t\t\tcase \"tenant__n\":\n\t\t\t\tparams.Tenantn = &vString\n\t\t\tcase \"tenant_group\":\n\t\t\t\tparams.TenantGroup = &vString\n\t\t\tcase \"tenant_group__n\":\n\t\t\t\tparams.TenantGroupn = &vString\n\t\t\tcase \"tenant_group_id\":\n\t\t\t\tparams.TenantGroupID = &vString\n\t\t\tcase \"tenant_group_id__n\":\n\t\t\t\tparams.TenantGroupIDn = &vString\n\t\t\tcase \"tenant_id\":\n\t\t\t\tparams.TenantID = &vString\n\t\t\tcase \"tenant_id__n\":\n\t\t\t\tparams.TenantIDn = &vString\n\t\t\tcase \"site_id\":\n\t\t\t\tparams.SiteID = &vString\n\t\t\tcase \"site_id__n\":\n\t\t\t\tparams.SiteIDn = &vString\n\t\t\tcase \"status\":\n\t\t\t\tparams.Status = &vString\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allVlans []*models.VLAN\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Ipam.IpamVlansList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch VLANs at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallVlans = append(allVlans, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allVlans)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allVlans))\n\tfilteredVlans := allVlans[:trimmedCount]\n\n\tif len(filteredVlans) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredVlans {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = v.ID\n\t\tmapping[\"vid\"] = v.Vid\n\t\tmapping[\"name\"] = v.Name\n\t\tmapping[\"description\"] = v.Description\n\t\tif v.Group != nil {\n\t\t\tmapping[\"group_id\"] = v.Group.ID\n\t\t}\n\t\tmapping[\"vid\"] = v.Vid\n\t\tif v.Role != nil {\n\t\t\tmapping[\"role\"] = v.Role.ID\n\t\t}\n\t\tif v.Site != nil {\n\t\t\tmapping[\"site\"] = v.Site.ID\n\t\t}\n\t\tmapping[\"status\"] = v.Status.Value\n\t\tif v.Tenant != nil {\n\t\t\tmapping[\"tenant\"] = v.Tenant.ID\n\t\t}\n\t\tif v.Tags != nil {\n\t\t\tvar tagIDs []int64\n\t\t\tfor _, t := range v.Tags {\n\t\t\t\ttagIDs = append(tagIDs, t.ID)\n\t\t\t}\n\t\t\tmapping[\"tag_ids\"] = tagIDs\n\t\t}\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"vlans\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vlans_test.go",
    "content": "package netbox\n\nimport (\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxVlansSetUp() string {\n\treturn `\nresource \"netbox_vlan\" \"test_1\" {\n  name = \"VLAN1234\"\n  vid  = 1234\n}\n\nresource \"netbox_vlan\" \"test_2\" {\n  name = \"VLAN1235\"\n  vid  = 1235\n}\n\nresource \"netbox_vlan\" \"test_3\" {\n  name = \"VLAN1236\"\n  vid  = 1236\n}`\n}\n\nfunc testAccNetboxVlansByVid() string {\n\treturn `\ndata \"netbox_vlans\" \"test\" {\n  filter {\n\tname  = \"vid\"\n\tvalue = \"1234\"\n  }\n}`\n}\n\nfunc testAccNetboxVlansByVidN() string {\n\treturn `\ndata \"netbox_vlans\" \"test\" {\n  filter {\n\tname = \"vid__n\"\n\tvalue = \"1234\"\n  }\n}`\n}\n\nfunc testAccNetboxVlansByVidRange() string {\n\treturn `\ndata \"netbox_vlans\" \"test\" {\n  filter {\n\tname = \"vid__gte\"\n\tvalue = \"1235\"\n  }\n\n  filter {\n\tname = \"vid__lte\"\n\tvalue = \"1236\"\n  }\n}`\n}\n\nfunc TestAccNetboxVlansDataSource_basic(t *testing.T) {\n\tsetUp := testAccNetboxVlansSetUp()\n\t// This test cannot be run in parallel with other tests, because other tests create also Vlans\n\t// These Vlans then interfere with the __n filter test\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_1\", \"vid\", \"1234\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlansByVid(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlans.test\", \"vlans.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlans.test\", \"vlans.0.id\", \"netbox_vlan.test_1\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlansByVid(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlans.test\", \"vlans.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlans.test\", \"vlans.0.vid\", \"netbox_vlan.test_1\", \"vid\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlansByVidN(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlans.test\", \"vlans.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlans.test\", \"vlans.0.vid\", \"netbox_vlan.test_2\", \"vid\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVlansByVidRange(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vlans.test\", \"vlans.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlans.test\", \"vlans.0.vid\", \"netbox_vlan.test_2\", \"vid\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vlans.test\", \"vlans.1.vid\", \"netbox_vlan.test_3\", \"vid\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vrf.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc dataSourceNetboxVrf() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxVrfRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxVrfRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparams := ipam.NewIpamVrfsListParams()\n\tparams.Name = &name\n\tlimit := int64(2) // Limit of 2 is enough\n\tparams.Limit = &limit\n\n\tif tenantID, ok := d.Get(\"tenant_id\").(int); ok && tenantID != 0 {\n\t\t// Note that tenant_id is a string pointer in the netbox filter, but we use a number in the provider\n\t\tparams.TenantID = strToPtr(strconv.Itoa(tenantID))\n\t}\n\n\tres, err := api.Ipam.IpamVrfsList(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif *res.GetPayload().Count > int64(1) {\n\t\treturn errors.New(\"more than one vrf returned, specify a more narrow filter\")\n\t}\n\tif *res.GetPayload().Count == int64(0) {\n\t\treturn errors.New(\"no vrf found matching filter\")\n\t}\n\tresult := res.GetPayload().Results[0]\n\td.SetId(strconv.FormatInt(result.ID, 10))\n\td.Set(\"name\", result.Name)\n\tif result.Tenant != nil {\n\t\td.Set(\"tenant_id\", result.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vrf_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxVrfDataSource_basic(t *testing.T) {\n\ttestSlug := \"vrf_ds_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tsimpleSetup := testAccNetboxVrfSetUp(testName)\n\tadvancedSetup := testAccNetboxVrfAdvancedSetUp(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: simpleSetup + testAccNetboxVrfData(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vrf.test\", \"id\", \"netbox_vrf.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      simpleSetup + advancedSetup + testAccNetboxVrfData(testName),\n\t\t\t\tExpectError: regexp.MustCompile(\"more than one vrf returned, specify a more narrow filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig:      advancedSetup + testAccNetboxVrfDataWithoutTenantID(testName),\n\t\t\t\tExpectError: regexp.MustCompile(\"more than one vrf returned, specify a more narrow filter\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: simpleSetup + advancedSetup + testAccNetboxVrfDataWithTenantID(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vrf.vrf_a\", \"id\", \"netbox_vrf.vrf_a\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vrf.vrf_b\", \"id\", \"netbox_vrf.vrf_b\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxVrfSetUp(testName string) string {\n\treturn fmt.Sprintf(`\nresource\"netbox_vrf\" \"test\" {\n  name = \"%[1]s\"\n}`, testName)\n}\n\nfunc testAccNetboxVrfData(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vrf\" \"test\" {\n  depends_on = [netbox_vrf.test]\n  name = \"%[1]s\"\n}`, testName)\n}\n\nfunc testAccNetboxVrfAdvancedSetUp(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"tenant_a\" {\n\tname = \"%[1]s-a\"\n}\n\nresource \"netbox_tenant\" \"tenant_b\" {\n\tname = \"%[1]s-b\"\n}\n\nresource \"netbox_vrf\" \"vrf_a\" {\n\tname      = \"%[1]s\"\n\ttenant_id = netbox_tenant.tenant_a.id\n}\n\nresource \"netbox_vrf\" \"vrf_b\" {\n\tname      = \"%[1]s\"\n\ttenant_id = netbox_tenant.tenant_b.id\n}\n`, testName)\n}\n\nfunc testAccNetboxVrfDataWithoutTenantID(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vrf\" \"vrf_a\" {\n\tname       = \"%[1]s\"\n}\n`, testName)\n}\n\nfunc testAccNetboxVrfDataWithTenantID(testName string) string {\n\treturn fmt.Sprintf(`\ndata \"netbox_vrf\" \"vrf_a\" {\n\tname       = \"%[1]s\"\n\ttenant_id  = netbox_tenant.tenant_a.id\n}\ndata \"netbox_vrf\" \"vrf_b\" {\n\tname       = \"%[1]s\"\n\ttenant_id  = netbox_tenant.tenant_b.id\n}\n`, testName)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vrfs.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc dataSourceNetboxVrfs() *schema.Resource {\n\treturn &schema.Resource{\n\t\tRead:        dataSourceNetboxVrfsRead,\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"filter\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tRequired: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"limit\": {\n\t\t\t\tType:             schema.TypeInt,\n\t\t\t\tOptional:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),\n\t\t\t\tDefault:          0,\n\t\t\t},\n\t\t\t\"vrfs\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"rd\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tenant\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc dataSourceNetboxVrfsRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparams := ipam.NewIpamVrfsListParams()\n\n\t// Get user limit\n\tvar userLimit int64 = 0\n\tif limitValue, ok := d.GetOk(\"limit\"); ok {\n\t\tuserLimit = int64(limitValue.(int))\n\t}\n\n\tif filter, ok := d.GetOk(\"filter\"); ok {\n\t\tvar filterParams = filter.(*schema.Set)\n\t\tvar tags []string\n\t\tfor _, f := range filterParams.List() {\n\t\t\tk := f.(map[string]interface{})[\"name\"]\n\t\t\tv := f.(map[string]interface{})[\"value\"]\n\t\t\tvString := v.(string)\n\t\t\tswitch k {\n\t\t\tcase \"id\":\n\t\t\t\tparams.ID = &vString\n\t\t\tcase \"name\":\n\t\t\t\tparams.Name = &vString\n\t\t\tcase \"description\":\n\t\t\t\tparams.Description = &vString\n\t\t\tcase \"rd\":\n\t\t\t\tparams.Rd = &vString\n\t\t\tcase \"tenant\":\n\t\t\t\tparams.Tenant = &vString\n\t\t\tcase \"tenant__n\":\n\t\t\t\tparams.Tenantn = &vString\n\t\t\tcase \"tenant_group\":\n\t\t\t\tparams.TenantGroup = &vString\n\t\t\tcase \"tenant_group__n\":\n\t\t\t\tparams.TenantGroupn = &vString\n\t\t\tcase \"tenant_group_id\":\n\t\t\t\tparams.TenantGroupID = &vString\n\t\t\tcase \"tenant_group_id__n\":\n\t\t\t\tparams.TenantGroupIDn = &vString\n\t\t\tcase \"tenant_id\":\n\t\t\t\tparams.TenantID = &vString\n\t\t\tcase \"tenant_id__n\":\n\t\t\t\tparams.TenantIDn = &vString\n\t\t\tcase \"tag\":\n\t\t\t\ttags = append(tags, vString)\n\t\t\t\tparams.Tag = tags\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"'%s' is not a supported filter parameter\", k)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fetch all pages with pagination\n\tpaginationHelper := NewPaginationHelper(userLimit)\n\tvar allVrfs []*models.VRF\n\n\tpageSize := paginationHelper.GetPageSize()\n\tfor {\n\t\tcurrentOffset := paginationHelper.CurrentOffset()\n\t\tparams.Limit = &pageSize\n\t\tparams.Offset = &currentOffset\n\n\t\tres, err := api.Ipam.IpamVrfsList(params, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch VRFs at offset %d: %w\", currentOffset, err)\n\t\t}\n\n\t\tpayload := res.GetPayload()\n\t\tallVrfs = append(allVrfs, payload.Results...)\n\n\t\tif len(payload.Results) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif !paginationHelper.ShouldContinuePaging(int64(len(allVrfs)), payload.Next) {\n\t\t\tbreak\n\t\t}\n\n\t\tpaginationHelper.Advance(int64(len(payload.Results)))\n\t}\n\n\t// Trim to user limit if specified\n\ttrimmedCount := paginationHelper.TrimToLimit(len(allVrfs))\n\tfilteredVrfs := allVrfs[:trimmedCount]\n\n\tif len(filteredVrfs) == 0 {\n\t\treturn errors.New(\"no result\")\n\t}\n\n\tvar s []map[string]interface{}\n\tfor _, v := range filteredVrfs {\n\t\tvar mapping = make(map[string]interface{})\n\n\t\tmapping[\"id\"] = v.ID\n\t\tmapping[\"name\"] = v.Name\n\t\tmapping[\"description\"] = v.Description\n\t\tif v.Rd != nil {\n\t\t\tmapping[\"rd\"] = v.Rd\n\t\t}\n\t\tif v.Tenant != nil {\n\t\t\tmapping[\"tenant\"] = v.Tenant.ID\n\t\t}\n\n\t\ts = append(s, mapping)\n\t}\n\n\td.SetId(id.UniqueId())\n\treturn d.Set(\"vrfs\", s)\n}\n"
  },
  {
    "path": "netbox/data_source_netbox_vrfs_test.go",
    "content": "package netbox\n\nimport (\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxVrfsSetUp() string {\n\treturn `\nresource \"netbox_tag\" \"test\" {\n  name = \"test_tag\"\n}\n\nresource \"netbox_vrf\" \"test_1\" {\n  name = \"VRF1\"\n}\n\nresource \"netbox_vrf\" \"test_2\" {\n  name = \"VRF2\"\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_vrf\" \"test_3\" {\n  name = \"VRF3\"\n}`\n}\n\nfunc testAccNetboxVrfsByName() string {\n\treturn `\ndata \"netbox_vrfs\" \"test\" {\n  filter {\n\tname  = \"name\"\n\tvalue = \"VRF1\"\n  }\n}`\n}\n\nfunc testAccNetboxVrfsByTag() string {\n\treturn `\ndata \"netbox_vrfs\" \"test\" {\n  filter {\n\tname  = \"tag\"\n\tvalue = netbox_tag.test.name\n  }\n}`\n}\n\nfunc TestAccNetboxVrfsDataSource_basic(t *testing.T) {\n\tsetUp := testAccNetboxVrfsSetUp()\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_1\", \"name\", \"VRF1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_2\", \"name\", \"VRF2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_3\", \"name\", \"VRF3\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVrfsByName(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vrfs.test\", \"vrfs.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vrfs.test\", \"vrfs.0.name\", \"netbox_vrf.test_1\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxVrfsByTag(),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"data.netbox_vrfs.test\", \"vrfs.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"data.netbox_vrfs.test\", \"vrfs.0.name\", \"netbox_vrf.test_2\", \"name\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/generic_objects.go",
    "content": "package netbox\n\nimport (\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar genericObjectSchema = &schema.Resource{\n\tSchema: map[string]*schema.Schema{\n\t\t\"object_type\": {\n\t\t\tType:     schema.TypeString,\n\t\t\tRequired: true,\n\t\t\tValidateFunc: validation.StringInSlice([]string{\n\t\t\t\t// known supported generic objects (wherever the schema is used)\n\t\t\t\t// can be made into a parameter when importing this schema if desired\n\t\t\t\t\"dcim.powerport\",\n\t\t\t\t\"dcim.poweroutlet\",\n\t\t\t\t\"dcim.powerfeed\",\n\t\t\t\t\"dcim.frontport\",\n\t\t\t\t\"dcim.rearport\",\n\t\t\t\t\"dcim.consoleserverport\",\n\t\t\t\t\"dcim.consoleport\",\n\t\t\t\t\"dcim.interface\",\n\t\t\t\t\"circuits.circuittermination\",\n\t\t\t}, false),\n\t\t},\n\t\t\"object_id\": {\n\t\t\tType:     schema.TypeInt,\n\t\t\tRequired: true,\n\t\t},\n\t},\n}\n\nfunc getGenericObjectsFromSchemaSet(schemaSet *schema.Set) []*models.GenericObject {\n\tretArr := make([]*models.GenericObject, 0, schemaSet.Len())\n\tfor _, i := range schemaSet.List() {\n\t\tretArr = append(retArr, &models.GenericObject{\n\t\t\tObjectID:   int64ToPtr(int64(i.(map[string]interface{})[\"object_id\"].(int))),\n\t\t\tObjectType: strToPtr(i.(map[string]interface{})[\"object_type\"].(string)),\n\t\t})\n\t}\n\treturn retArr\n}\n\nfunc getSchemaSetFromGenericObjects(objects []*models.GenericObject) []map[string]interface{} {\n\tretArr := make([]map[string]interface{}, 0, len(objects))\n\tfor _, obj := range objects {\n\t\tmapping := make(map[string]interface{})\n\t\tmapping[\"object_type\"] = obj.ObjectType\n\t\tmapping[\"object_id\"] = obj.ObjectID\n\n\t\tretArr = append(retArr, mapping)\n\t}\n\treturn retArr\n}\n"
  },
  {
    "path": "netbox/netbox_sweeper_test.go",
    "content": "package netbox\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client\"\n\thttptransport \"github.com/go-openapi/runtime/client\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\n// sweeperNetboxClients is a shared cache of netbox clients\n// This prevents client re-initialization for every resource with no benefit\nvar sweeperNetboxClients map[string]interface{}\n\nfunc TestMain(m *testing.M) {\n\tresource.TestMain(m)\n}\n\n// sharedClientForRegion returns a common provider client configured for the specified region\nfunc sharedClientForRegion(region string) (interface{}, error) {\n\tif client, ok := sweeperNetboxClients[region]; ok {\n\t\treturn client, nil\n\t}\n\n\tserver := os.Getenv(\"NETBOX_SERVER\")\n\tapiToken := os.Getenv(\"NETBOX_API_TOKEN\")\n\ttransport := httptransport.New(server, client.DefaultBasePath, []string{\"http\"})\n\ttransport.DefaultAuthentication = httptransport.APIKeyAuth(\"Authorization\", \"header\", \"Token \"+apiToken)\n\tc := client.New(transport, nil)\n\n\treturn c, nil\n}\n"
  },
  {
    "path": "netbox/pagination.go",
    "content": "package netbox\n\nimport \"github.com/go-openapi/strfmt\"\n\nconst (\n\t// DefaultPageSize balances API response time, request count, and memory usage\n\tDefaultPageSize = 100\n\t// FetchAll instructs the pagination helper to fetch all results (no user-imposed limit)\n\tFetchAll int64 = 0\n)\n\n// PaginatedListHelper manages automatic pagination for NetBox API list endpoints\ntype PaginatedListHelper struct {\n\tuserLimit int64 // Maximum results to return (0 = fetch all)\n\tpageSize  int64 // Items per API request\n\toffset    int64 // Current offset, advanced by Advance()\n}\n\n// NewPaginationHelper creates a helper with the given user limit\nfunc NewPaginationHelper(userLimit int64) *PaginatedListHelper {\n\treturn &PaginatedListHelper{\n\t\tuserLimit: userLimit,\n\t\tpageSize:  DefaultPageSize,\n\t}\n}\n\n// CurrentOffset returns the offset to use for the next API request\nfunc (h *PaginatedListHelper) CurrentOffset() int64 {\n\treturn h.offset\n}\n\n// Advance moves the offset forward by the number of items returned in the last page.\n// Must be called with the actual returned count, not the requested page size, to correctly\n// handle servers that cap responses below the requested limit (NetBox MAX_PAGE_SIZE).\nfunc (h *PaginatedListHelper) Advance(returned int64) {\n\th.offset += returned\n}\n\n// ShouldContinuePaging determines if another page should be fetched\nfunc (h *PaginatedListHelper) ShouldContinuePaging(currentCount int64, next *strfmt.URI) bool {\n\tif h.userLimit > 0 && currentCount >= h.userLimit {\n\t\treturn false\n\t}\n\treturn next != nil && *next != \"\"\n}\n\n// TrimToLimit trims results to user's limit if specified\nfunc (h *PaginatedListHelper) TrimToLimit(count int) int {\n\tif h.userLimit > 0 && int64(count) > h.userLimit {\n\t\treturn int(h.userLimit)\n\t}\n\treturn count\n}\n\n// GetPageSize returns the configured page size\nfunc (h *PaginatedListHelper) GetPageSize() int64 {\n\treturn h.pageSize\n}\n"
  },
  {
    "path": "netbox/pagination_test.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/go-openapi/strfmt\"\n)\n\nfunc TestPaginationHelper_ShouldContinuePaging(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\tuserLimit    int64\n\t\tcurrentCount int64\n\t\tnext         *strfmt.URI\n\t\twant         bool\n\t}{\n\t\t{\n\t\t\tname:         \"no limit, has next\",\n\t\t\tuserLimit:    0,\n\t\t\tcurrentCount: 50,\n\t\t\tnext:         uriPtr(\"http://example.com/api?offset=50\"),\n\t\t\twant:         true,\n\t\t},\n\t\t{\n\t\t\tname:         \"no limit, no next\",\n\t\t\tuserLimit:    0,\n\t\t\tcurrentCount: 50,\n\t\t\tnext:         nil,\n\t\t\twant:         false,\n\t\t},\n\t\t{\n\t\t\tname:         \"no limit, empty next\",\n\t\t\tuserLimit:    0,\n\t\t\tcurrentCount: 50,\n\t\t\tnext:         uriPtr(\"\"),\n\t\t\twant:         false,\n\t\t},\n\t\t{\n\t\t\tname:         \"at limit, has next\",\n\t\t\tuserLimit:    100,\n\t\t\tcurrentCount: 100,\n\t\t\tnext:         uriPtr(\"http://example.com/api?offset=100\"),\n\t\t\twant:         false,\n\t\t},\n\t\t{\n\t\t\tname:         \"under limit, has next\",\n\t\t\tuserLimit:    100,\n\t\t\tcurrentCount: 50,\n\t\t\tnext:         uriPtr(\"http://example.com/api?offset=50\"),\n\t\t\twant:         true,\n\t\t},\n\t\t{\n\t\t\tname:         \"over limit, has next\",\n\t\t\tuserLimit:    100,\n\t\t\tcurrentCount: 150,\n\t\t\tnext:         uriPtr(\"http://example.com/api?offset=150\"),\n\t\t\twant:         false,\n\t\t},\n\t\t{\n\t\t\tname:         \"under limit, no next\",\n\t\t\tuserLimit:    100,\n\t\t\tcurrentCount: 50,\n\t\t\tnext:         nil,\n\t\t\twant:         false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\thelper := NewPaginationHelper(tt.userLimit)\n\t\t\tgot := helper.ShouldContinuePaging(tt.currentCount, tt.next)\n\t\t\tif got != tt.want {\n\t\t\t\tt.Errorf(\"ShouldContinuePaging() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPaginationHelper_TrimToLimit(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tuserLimit int64\n\t\tcount     int\n\t\twant      int\n\t}{\n\t\t{\n\t\t\tname:      \"no limit, no trim\",\n\t\t\tuserLimit: 0,\n\t\t\tcount:     150,\n\t\t\twant:      150,\n\t\t},\n\t\t{\n\t\t\tname:      \"under limit, no trim\",\n\t\t\tuserLimit: 100,\n\t\t\tcount:     50,\n\t\t\twant:      50,\n\t\t},\n\t\t{\n\t\t\tname:      \"at limit, no trim\",\n\t\t\tuserLimit: 100,\n\t\t\tcount:     100,\n\t\t\twant:      100,\n\t\t},\n\t\t{\n\t\t\tname:      \"over limit, trim to limit\",\n\t\t\tuserLimit: 100,\n\t\t\tcount:     150,\n\t\t\twant:      100,\n\t\t},\n\t\t{\n\t\t\tname:      \"way over limit, trim to limit\",\n\t\t\tuserLimit: 50,\n\t\t\tcount:     500,\n\t\t\twant:      50,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\thelper := NewPaginationHelper(tt.userLimit)\n\t\t\tgot := helper.TrimToLimit(tt.count)\n\t\t\tif got != tt.want {\n\t\t\t\tt.Errorf(\"TrimToLimit() = %d, want %d\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPaginationHelper_GetPageSize(t *testing.T) {\n\thelper := NewPaginationHelper(0)\n\tif got := helper.GetPageSize(); got != DefaultPageSize {\n\t\tt.Errorf(\"GetPageSize() = %d, want %d\", got, DefaultPageSize)\n\t}\n}\n\n// TestPaginationHelper_ServerCapOffset verifies correct offset advancement when a\n// NetBox server has MAX_PAGE_SIZE set below DefaultPageSize (100). In that case the\n// server returns fewer items per page than requested, so the offset must advance by\n// len(results) — not by the requested page size — to avoid skipping items.\n//\n// Example: MAX_PAGE_SIZE=50, DefaultPageSize=100, total=150 items\n//\n// Correct (offset += len(results)=50):\n//\n//\treq offset=0   → server returns 50 items (0–49),  offset becomes 50\n//\treq offset=50  → server returns 50 items (50–99),  offset becomes 100\n//\treq offset=100 → server returns 50 items (100–149), done\n//\tcollected: 150 ✓\n//\n// Incorrect (offset += pageSize=100):\n//\n//\treq offset=0   → server returns 50 items (0–49),  offset becomes 100\n//\treq offset=100 → server returns 50 items (100–149), done\n//\tcollected: 100 — items 50–99 silently skipped\nfunc TestPaginationHelper_ServerCapOffset(t *testing.T) {\n\t// simulatePage mimics NetBox's OptionalLimitOffsetPagination:\n\t// returns min(serverCap, requestedLimit, remaining) items and whether a next page exists.\n\tsimulatePage := func(totalItems, serverCap, offset, requestedLimit int) (returned int, next *strfmt.URI) {\n\t\tactualLimit := requestedLimit\n\t\tif serverCap < actualLimit {\n\t\t\tactualLimit = serverCap\n\t\t}\n\t\tremaining := totalItems - offset\n\t\tif remaining <= 0 {\n\t\t\treturn 0, nil\n\t\t}\n\t\treturned = actualLimit\n\t\tif remaining < returned {\n\t\t\treturned = remaining\n\t\t}\n\t\tif offset+returned < totalItems {\n\t\t\tu := strfmt.URI(\"http://netbox/api/?offset=\" + strconv.Itoa(offset+returned))\n\t\t\treturn returned, &u\n\t\t}\n\t\treturn returned, nil\n\t}\n\n\ttests := []struct {\n\t\tname          string\n\t\ttotalItems    int\n\t\tserverCap     int // simulates NetBox MAX_PAGE_SIZE\n\t\twantCollected int\n\t}{\n\t\t{\n\t\t\t// 50+50+30 — last page is partial\n\t\t\tname:          \"server cap below page size\",\n\t\t\ttotalItems:    130,\n\t\t\tserverCap:     50,\n\t\t\twantCollected: 130,\n\t\t},\n\t\t{\n\t\t\t// 100+100+10 — last page is partial\n\t\t\tname:          \"server cap equal to page size\",\n\t\t\ttotalItems:    210,\n\t\t\tserverCap:     100,\n\t\t\twantCollected: 210,\n\t\t},\n\t\t{\n\t\t\t// 100+30 — last page is partial\n\t\t\tname:          \"server cap above page size\",\n\t\t\ttotalItems:    130,\n\t\t\tserverCap:     1000,\n\t\t\twantCollected: 130,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tpageSize := int(DefaultPageSize)\n\t\t\thelper := NewPaginationHelper(FetchAll)\n\t\t\tcollected := 0\n\t\t\tfor {\n\t\t\t\treturned, next := simulatePage(tt.totalItems, tt.serverCap, int(helper.CurrentOffset()), pageSize)\n\t\t\t\tcollected += returned\n\t\t\t\tif returned == 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif !helper.ShouldContinuePaging(int64(collected), next) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\thelper.Advance(int64(returned))\n\t\t\t}\n\t\t\tif collected != tt.wantCollected {\n\t\t\t\tt.Errorf(\"collected %d, want %d\", collected, tt.wantCollected)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// Helper function to create URI pointers for tests\nfunc uriPtr(s string) *strfmt.URI {\n\turi := strfmt.URI(s)\n\treturn &uri\n}\n"
  },
  {
    "path": "netbox/provider.go",
    "content": "package netbox\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client\"\n\t\"github.com/fbreckle/go-netbox/netbox/client/status\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"golang.org/x/exp/slices\"\n)\n\ntype providerState struct {\n\t*client.NetBoxAPI\n\tdefaultTags *schema.Set\n\n\t// concurrent access ok, only populated on provider start\n\ttagCache map[string]*models.NestedTag\n}\n\n// This makes the description contain the default value, particularly useful for the docs\n// From https://github.com/hashicorp/terraform-plugin-docs/issues/65#issuecomment-1152842370\nfunc init() {\n\tschema.DescriptionKind = schema.StringMarkdown\n\n\tschema.SchemaDescriptionBuilder = func(s *schema.Schema) string {\n\t\tdesc := s.Description\n\t\tdesc = strings.TrimSpace(desc)\n\n\t\tif !bytes.HasSuffix([]byte(s.Description), []byte(\".\")) && s.Description != \"\" {\n\t\t\tdesc += \".\"\n\t\t}\n\n\t\tif len(s.AtLeastOneOf) > 0 {\n\t\t\tatLeastOneOf := make([]string, len(s.AtLeastOneOf))\n\t\t\tfor i, l := range s.AtLeastOneOf {\n\t\t\t\tatLeastOneOf[i] = fmt.Sprintf(\"`%s`\", l)\n\t\t\t}\n\t\t\tdesc += fmt.Sprintf(\" At least one of %s must be given.\", joinStringWithFinalConjunction(atLeastOneOf, \", \", \"or\"))\n\t\t}\n\n\t\tif len(s.ExactlyOneOf) > 0 {\n\t\t\texactlyOneOf := make([]string, len(s.ExactlyOneOf))\n\t\t\tfor i, l := range s.ExactlyOneOf {\n\t\t\t\texactlyOneOf[i] = fmt.Sprintf(\"`%s`\", l)\n\t\t\t}\n\t\t\tdesc += fmt.Sprintf(\" Exactly one of %s must be given.\", joinStringWithFinalConjunction(exactlyOneOf, \", \", \"or\"))\n\t\t}\n\n\t\tif len(s.RequiredWith) > 0 {\n\t\t\trequires := make([]string, len(s.RequiredWith))\n\t\t\tfor i, c := range s.RequiredWith {\n\t\t\t\trequires[i] = fmt.Sprintf(\"`%s`\", c)\n\t\t\t}\n\t\t\tdesc += fmt.Sprintf(\" Required when %s is set.\", joinStringWithFinalConjunction(requires, \", \", \"and\"))\n\t\t}\n\n\t\tif len(s.ConflictsWith) > 0 {\n\t\t\tconflicts := make([]string, len(s.ConflictsWith))\n\t\t\tfor i, c := range s.ConflictsWith {\n\t\t\t\tconflicts[i] = fmt.Sprintf(\"`%s`\", c)\n\t\t\t}\n\t\t\tdesc += fmt.Sprintf(\" Conflicts with %s.\", joinStringWithFinalConjunction(conflicts, \", \", \"and\"))\n\t\t}\n\n\t\tif s.Default != nil {\n\t\t\tif s.Default == \"\" {\n\t\t\t\tdesc += \" Defaults to `\\\"\\\"`.\"\n\t\t\t} else {\n\t\t\t\tdesc += fmt.Sprintf(\" Defaults to `%v`.\", s.Default)\n\t\t\t}\n\t\t}\n\n\t\treturn strings.TrimSpace(desc)\n\t}\n}\n\n// Provider returns a schema.Provider for Netbox.\nfunc Provider() *schema.Provider {\n\tprovider := &schema.Provider{\n\t\tResourcesMap: map[string]*schema.Resource{\n\t\t\t\"netbox_available_ip_address\":       resourceNetboxAvailableIPAddress(),\n\t\t\t\"netbox_virtual_machine\":            resourceNetboxVirtualMachine(),\n\t\t\t\"netbox_cluster_type\":               resourceNetboxClusterType(),\n\t\t\t\"netbox_cluster\":                    resourceNetboxCluster(),\n\t\t\t\"netbox_contact\":                    resourceNetboxContact(),\n\t\t\t\"netbox_contact_group\":              resourceNetboxContactGroup(),\n\t\t\t\"netbox_contact_assignment\":         resourceNetboxContactAssignment(),\n\t\t\t\"netbox_contact_role\":               resourceNetboxContactRole(),\n\t\t\t\"netbox_device\":                     resourceNetboxDevice(),\n\t\t\t\"netbox_device_interface\":           resourceNetboxDeviceInterface(),\n\t\t\t\"netbox_device_type\":                resourceNetboxDeviceType(),\n\t\t\t\"netbox_manufacturer\":               resourceNetboxManufacturer(),\n\t\t\t\"netbox_tenant\":                     resourceNetboxTenant(),\n\t\t\t\"netbox_tenant_group\":               resourceNetboxTenantGroup(),\n\t\t\t\"netbox_vrf\":                        resourceNetboxVrf(),\n\t\t\t\"netbox_ip_address\":                 resourceNetboxIPAddress(),\n\t\t\t\"netbox_interface_template\":         resourceNetboxInterfaceTemplate(),\n\t\t\t\"netbox_interface\":                  resourceNetboxInterface(),\n\t\t\t\"netbox_service\":                    resourceNetboxService(),\n\t\t\t\"netbox_platform\":                   resourceNetboxPlatform(),\n\t\t\t\"netbox_prefix\":                     resourceNetboxPrefix(),\n\t\t\t\"netbox_available_prefix\":           resourceNetboxAvailablePrefix(),\n\t\t\t\"netbox_primary_ip\":                 resourceNetboxPrimaryIP(),\n\t\t\t\"netbox_device_primary_ip\":          resourceNetboxDevicePrimaryIP(),\n\t\t\t\"netbox_device_role\":                resourceNetboxDeviceRole(),\n\t\t\t\"netbox_tag\":                        resourceNetboxTag(),\n\t\t\t\"netbox_cluster_group\":              resourceNetboxClusterGroup(),\n\t\t\t\"netbox_site\":                       resourceNetboxSite(),\n\t\t\t\"netbox_vlan\":                       resourceNetboxVlan(),\n\t\t\t\"netbox_vlan_group\":                 resourceNetboxVlanGroup(),\n\t\t\t\"netbox_available_vlan\":             resourceNetboxAvailableVLAN(),\n\t\t\t\"netbox_ipam_role\":                  resourceNetboxIpamRole(),\n\t\t\t\"netbox_ip_range\":                   resourceNetboxIPRange(),\n\t\t\t\"netbox_region\":                     resourceNetboxRegion(),\n\t\t\t\"netbox_aggregate\":                  resourceNetboxAggregate(),\n\t\t\t\"netbox_rir\":                        resourceNetboxRir(),\n\t\t\t\"netbox_route_target\":               resourceNetboxRouteTarget(),\n\t\t\t\"netbox_circuit\":                    resourceNetboxCircuit(),\n\t\t\t\"netbox_circuit_type\":               resourceNetboxCircuitType(),\n\t\t\t\"netbox_circuit_provider\":           resourceNetboxCircuitProvider(),\n\t\t\t\"netbox_circuit_termination\":        resourceNetboxCircuitTermination(),\n\t\t\t\"netbox_user\":                       resourceNetboxUser(),\n\t\t\t\"netbox_group\":                      resourceNetboxGroup(),\n\t\t\t\"netbox_permission\":                 resourceNetboxPermission(),\n\t\t\t\"netbox_token\":                      resourceNetboxToken(),\n\t\t\t\"netbox_custom_field\":               resourceCustomField(),\n\t\t\t\"netbox_asn\":                        resourceNetboxAsn(),\n\t\t\t\"netbox_location\":                   resourceNetboxLocation(),\n\t\t\t\"netbox_site_group\":                 resourceNetboxSiteGroup(),\n\t\t\t\"netbox_rack\":                       resourceNetboxRack(),\n\t\t\t\"netbox_rack_type\":                  resourceNetboxRackType(),\n\t\t\t\"netbox_rack_role\":                  resourceNetboxRackRole(),\n\t\t\t\"netbox_rack_reservation\":           resourceNetboxRackReservation(),\n\t\t\t\"netbox_cable\":                      resourceNetboxCable(),\n\t\t\t\"netbox_device_console_port\":        resourceNetboxDeviceConsolePort(),\n\t\t\t\"netbox_device_console_server_port\": resourceNetboxDeviceConsoleServerPort(),\n\t\t\t\"netbox_device_power_port\":          resourceNetboxDevicePowerPort(),\n\t\t\t\"netbox_device_power_outlet\":        resourceNetboxDevicePowerOutlet(),\n\t\t\t\"netbox_device_front_port\":          resourceNetboxDeviceFrontPort(),\n\t\t\t\"netbox_device_rear_port\":           resourceNetboxDeviceRearPort(),\n\t\t\t\"netbox_device_module_bay\":          resourceNetboxDeviceModuleBay(),\n\t\t\t\"netbox_device_bay\":                 resourceNetboxDeviceBay(),\n\t\t\t\"netbox_device_bay_template\":        resourceNetboxDeviceBayTemplate(),\n\t\t\t\"netbox_module\":                     resourceNetboxModule(),\n\t\t\t\"netbox_module_type\":                resourceNetboxModuleType(),\n\t\t\t\"netbox_power_feed\":                 resourceNetboxPowerFeed(),\n\t\t\t\"netbox_power_panel\":                resourceNetboxPowerPanel(),\n\t\t\t\"netbox_inventory_item_role\":        resourceNetboxInventoryItemRole(),\n\t\t\t\"netbox_inventory_item\":             resourceNetboxInventoryItem(),\n\t\t\t\"netbox_webhook\":                    resourceNetboxWebhook(),\n\t\t\t\"netbox_custom_field_choice_set\":    resourceNetboxCustomFieldChoiceSet(),\n\t\t\t\"netbox_virtual_chassis\":            resourceNetboxVirtualChassis(),\n\t\t\t\"netbox_virtual_disk\":               resourceNetboxVirtualDisks(),\n\t\t\t\"netbox_config_template\":            resourceNetboxConfigTemplate(),\n\t\t\t\"netbox_event_rule\":                 resourceNetboxEventRule(),\n\t\t\t\"netbox_vpn_tunnel_group\":           resourceNetboxVpnTunnelGroup(),\n\t\t\t\"netbox_vpn_tunnel\":                 resourceNetboxVpnTunnel(),\n\t\t\t\"netbox_vpn_tunnel_termination\":     resourceNetboxVpnTunnelTermination(),\n\t\t\t\"netbox_config_context\":             resourceNetboxConfigContext(),\n\t\t\t\"netbox_mac_address\":                resourceNetboxMACAddress(),\n\t\t\t\"netbox_wireless_lan_group\":         resourceNetboxWirelessLANGroup(),\n\t\t\t\"netbox_wireless_lan\":               resourceNetboxWirelessLAN(),\n\t\t},\n\t\tDataSourcesMap: map[string]*schema.Resource{\n\t\t\t\"netbox_asn\":                  dataSourceNetboxAsn(),\n\t\t\t\"netbox_asns\":                 dataSourceNetboxAsns(),\n\t\t\t\"netbox_available_prefix\":     dataSourceNetboxAvailablePrefix(),\n\t\t\t\"netbox_cluster\":              dataSourceNetboxCluster(),\n\t\t\t\"netbox_clusters\":             dataSourceNetboxClusters(),\n\t\t\t\"netbox_cluster_group\":        dataSourceNetboxClusterGroup(),\n\t\t\t\"netbox_cluster_type\":         dataSourceNetboxClusterType(),\n\t\t\t\"netbox_contact\":              dataSourceNetboxContact(),\n\t\t\t\"netbox_contact_role\":         dataSourceNetboxContactRole(),\n\t\t\t\"netbox_contact_group\":        dataSourceNetboxContactGroup(),\n\t\t\t\"netbox_tenant\":               dataSourceNetboxTenant(),\n\t\t\t\"netbox_tenants\":              dataSourceNetboxTenants(),\n\t\t\t\"netbox_tenant_group\":         dataSourceNetboxTenantGroup(),\n\t\t\t\"netbox_vrf\":                  dataSourceNetboxVrf(),\n\t\t\t\"netbox_vrfs\":                 dataSourceNetboxVrfs(),\n\t\t\t\"netbox_platform\":             dataSourceNetboxPlatform(),\n\t\t\t\"netbox_prefix\":               dataSourceNetboxPrefix(),\n\t\t\t\"netbox_prefixes\":             dataSourceNetboxPrefixes(),\n\t\t\t\"netbox_devices\":              dataSourceNetboxDevices(),\n\t\t\t\"netbox_device_role\":          dataSourceNetboxDeviceRole(),\n\t\t\t\"netbox_device_type\":          dataSourceNetboxDeviceType(),\n\t\t\t\"netbox_site\":                 dataSourceNetboxSite(),\n\t\t\t\"netbox_location\":             dataSourceNetboxLocation(),\n\t\t\t\"netbox_locations\":            dataSourceNetboxLocations(),\n\t\t\t\"netbox_tag\":                  dataSourceNetboxTag(),\n\t\t\t\"netbox_tags\":                 dataSourceNetboxTags(),\n\t\t\t\"netbox_virtual_machines\":     dataSourceNetboxVirtualMachine(),\n\t\t\t\"netbox_interfaces\":           dataSourceNetboxInterfaces(),\n\t\t\t\"netbox_device_interfaces\":    dataSourceNetboxDeviceInterfaces(),\n\t\t\t\"netbox_device_power_ports\":   dataSourceNetboxDevicePowerPorts(),\n\t\t\t\"netbox_ipam_role\":            dataSourceNetboxIPAMRole(),\n\t\t\t\"netbox_route_target\":         dataSourceNetboxRouteTarget(),\n\t\t\t\"netbox_ip_address\":           dataSourceNetboxIPAddress(),\n\t\t\t\"netbox_ip_addresses\":         dataSourceNetboxIPAddresses(),\n\t\t\t\"netbox_ip_range\":             dataSourceNetboxIPRange(),\n\t\t\t\"netbox_ip_ranges\":            dataSourceNetboxIPRanges(),\n\t\t\t\"netbox_region\":               dataSourceNetboxRegion(),\n\t\t\t\"netbox_rir\":                  dataSourceNetboxRir(),\n\t\t\t\"netbox_vlan\":                 dataSourceNetboxVlan(),\n\t\t\t\"netbox_vlans\":                dataSourceNetboxVlans(),\n\t\t\t\"netbox_vlan_group\":           dataSourceNetboxVlanGroup(),\n\t\t\t\"netbox_vlan_groups\":          dataSourceNetboxVlanGroups(),\n\t\t\t\"netbox_site_group\":           dataSourceNetboxSiteGroup(),\n\t\t\t\"netbox_racks\":                dataSourceNetboxRacks(),\n\t\t\t\"netbox_rack_role\":            dataSourceNetboxRackRole(),\n\t\t\t\"netbox_config_context\":       dataSourceNetboxConfigContext(),\n\t\t\t\"netbox_virtual_disk\":         dataSourceNetboxVirtualDisk(),\n\t\t\t\"netbox_device_render_config\": dataSourceNetboxDeviceRenderConfig(),\n\t\t},\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"server_url\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tRequired:    true,\n\t\t\t\tDefaultFunc: schema.EnvDefaultFunc(\"NETBOX_SERVER_URL\", nil),\n\t\t\t\tDescription: \"Location of Netbox server including scheme (http or https) and optional port. Can be set via the `NETBOX_SERVER_URL` environment variable.\",\n\t\t\t},\n\t\t\t\"api_token\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tRequired:    true,\n\t\t\t\tDefaultFunc: schema.EnvDefaultFunc(\"NETBOX_API_TOKEN\", nil),\n\t\t\t\tDescription: \"Netbox API authentication token. Supports both v1 tokens (`Authorization: Token <key>`) and v2 tokens (`Authorization: Bearer nbt_<key>.<token>`). V2 tokens are auto-detected by their `nbt_` prefix. Can be set via the `NETBOX_API_TOKEN` environment variable.\",\n\t\t\t},\n\t\t\t\"allow_insecure_https\": {\n\t\t\t\tType:        schema.TypeBool,\n\t\t\t\tOptional:    true,\n\t\t\t\tDefaultFunc: schema.EnvDefaultFunc(\"NETBOX_ALLOW_INSECURE_HTTPS\", false),\n\t\t\t\tDescription: \"Flag to set whether to allow https with invalid certificates. Can be set via the `NETBOX_ALLOW_INSECURE_HTTPS` environment variable. Defaults to `false`.\",\n\t\t\t},\n\t\t\t\"headers\": {\n\t\t\t\tType:        schema.TypeMap,\n\t\t\t\tOptional:    true,\n\t\t\t\tDefaultFunc: schema.EnvDefaultFunc(\"NETBOX_HEADERS\", map[string]interface{}{}),\n\t\t\t\tDescription: \"Set these header on all requests to Netbox. Can be set via the `NETBOX_HEADERS` environment variable.\",\n\t\t\t},\n\t\t\t\"strip_trailing_slashes_from_url\": {\n\t\t\t\tType:        schema.TypeBool,\n\t\t\t\tOptional:    true,\n\t\t\t\tDefaultFunc: schema.EnvDefaultFunc(\"NETBOX_STRIP_TRAILING_SLASHES_FROM_URL\", true),\n\t\t\t\tDescription: \"If true, strip trailing slashes from the `server_url` parameter and print a warning when doing so. Note that using trailing slashes in the `server_url` parameter will usually lead to errors. Can be set via the `NETBOX_STRIP_TRAILING_SLASHES_FROM_URL` environment variable. Defaults to `true`.\",\n\t\t\t},\n\t\t\t\"skip_version_check\": {\n\t\t\t\tType:        schema.TypeBool,\n\t\t\t\tOptional:    true,\n\t\t\t\tDefaultFunc: schema.EnvDefaultFunc(\"NETBOX_SKIP_VERSION_CHECK\", false),\n\t\t\t\tDescription: \"If true, do not try to determine the running Netbox version at provider startup. Disables warnings about possibly unsupported Netbox version. Also useful for local testing on terraform plans. Can be set via the `NETBOX_SKIP_VERSION_CHECK` environment variable. Defaults to `false`.\",\n\t\t\t},\n\t\t\t\"request_timeout\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tOptional:    true,\n\t\t\t\tDefaultFunc: schema.EnvDefaultFunc(\"NETBOX_REQUEST_TIMEOUT\", 10),\n\t\t\t\tDescription: \"Netbox API HTTP request timeout in seconds. Can be set via the `NETBOX_REQUEST_TIMEOUT` environment variable.\",\n\t\t\t},\n\t\t\t\"default_tags\": {\n\t\t\t\tType: schema.TypeSet,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"Tags to add to every resource managed by this provider\",\n\t\t\t},\n\t\t\t\"ca_cert_file\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDefaultFunc: schema.EnvDefaultFunc(\"NETBOX_CA_CERT_FILE\", nil),\n\t\t\t\tDescription: \"Path to a PEM-encoded CA certificate for verifying the Netbox server certificate. Can be set via the `NETBOX_CA_CERT_FILE` environment variable.\",\n\t\t\t},\n\t\t},\n\t\tConfigureContextFunc: providerConfigure,\n\t}\n\n\t// all resources that have tags get a custom diff function\n\tfor _, def := range provider.ResourcesMap {\n\t\tif _, ok := def.Schema[tagsKey]; ok {\n\t\t\tdef.Schema[tagsAllKey] = tagsAllSchema // add computed key for all tags\n\t\t\tif existingDiff := def.CustomizeDiff; existingDiff != nil {\n\t\t\t\tdef.CustomizeDiff = customdiff.Sequence(existingDiff, tagsCustomDiff)\n\t\t\t} else {\n\t\t\t\tdef.CustomizeDiff = tagsCustomDiff\n\t\t\t}\n\t\t}\n\t}\n\n\treturn provider\n}\n\nfunc providerConfigure(ctx context.Context, data *schema.ResourceData) (interface{}, diag.Diagnostics) {\n\tvar diags diag.Diagnostics\n\n\tconfig := Config{\n\t\tAPIToken:                    data.Get(\"api_token\").(string),\n\t\tAllowInsecureHTTPS:          data.Get(\"allow_insecure_https\").(bool),\n\t\tHeaders:                     data.Get(\"headers\").(map[string]interface{}),\n\t\tRequestTimeout:              data.Get(\"request_timeout\").(int),\n\t\tStripTrailingSlashesFromURL: data.Get(\"strip_trailing_slashes_from_url\").(bool),\n\t\tCACertFile:                  data.Get(\"ca_cert_file\").(string),\n\t}\n\n\tserverURL := data.Get(\"server_url\").(string)\n\n\t// Unless explicitly switched off, strip trailing slashes from the server url\n\t// Trailing slashes cause errors as seen in https://github.com/e-breuninger/terraform-provider-netbox/issues/198\n\t// and https://github.com/e-breuninger/terraform-provider-netbox/issues/300\n\tstripTrailingSlashesFromURL := data.Get(\"strip_trailing_slashes_from_url\").(bool)\n\n\tif stripTrailingSlashesFromURL {\n\t\ttrimmed := false\n\n\t\t// This is Go's poor man's while loop\n\t\tfor strings.HasSuffix(serverURL, \"/\") {\n\t\t\tserverURL = strings.TrimRight(serverURL, \"/\")\n\t\t\ttrimmed = true\n\t\t}\n\t\tif trimmed {\n\t\t\tdiags = append(diags, diag.Diagnostic{\n\t\t\t\tSeverity: diag.Warning,\n\t\t\t\tSummary:  \"Stripped trailing slashes from the `server_url` parameter\",\n\t\t\t\tDetail:   \"Trailing slashes in the `server_url` parameter lead to problems in most setups, so all trailing slashes were stripped. Use the `strip_trailing_slashes_from_url` parameter to disable this feature or remove all trailing slashes in the `server_url` to disable this warning.\",\n\t\t\t})\n\t\t}\n\t}\n\n\tconfig.ServerURL = serverURL\n\n\tnetboxClient, clientError := config.Client()\n\tif clientError != nil {\n\t\treturn nil, diag.FromErr(clientError)\n\t}\n\n\t// Unless explicitly switched off, use the client to retrieve the Netbox version\n\t// so we can determine compatibility of the provider with the used Netbox\n\tskipVersionCheck := data.Get(\"skip_version_check\").(bool)\n\n\tif !skipVersionCheck {\n\t\treq := status.NewStatusListParams()\n\t\tres, err := netboxClient.Status.StatusList(req, nil)\n\t\tif err != nil {\n\t\t\treturn nil, diag.FromErr(err)\n\t\t}\n\n\t\tnetboxVersionStringFromAPI := res.GetPayload().(map[string]interface{})[\"netbox-version\"].(string)\n\n\t\tnetboxVersion, err := extractSemanticVersionFromString(netboxVersionStringFromAPI)\n\t\tif err != nil {\n\t\t\treturn nil, diag.FromErr(fmt.Errorf(\"error extracting netbox version. try using the `skip_version_check` provider parameter to bypass this error. original error: %w\", err))\n\t\t}\n\n\t\tsupportedVersions := []string{\"4.3.0\", \"4.3.2\", \"4.3.3\", \"4.3.4\", \"4.3.5\", \"4.3.6\", \"4.3.7\", \"4.4.0\", \"4.4.1\", \"4.4.2\", \"4.4.4\", \"4.4.5\", \"4.4.6\", \"4.4.7\", \"4.4.8\", \"4.4.9\", \"4.4.10\"}\n\n\t\tif !slices.Contains(supportedVersions, netboxVersion) {\n\t\t\t// Currently, there is no way to test these warnings. There is an issue to track this: https://github.com/hashicorp/terraform-plugin-sdk/issues/864\n\t\t\tdiags = append(diags, diag.Diagnostic{\n\t\t\t\tSeverity: diag.Warning,\n\t\t\t\tSummary:  \"Possibly unsupported Netbox version\",\n\t\t\t\tDetail:   fmt.Sprintf(\"Your Netbox reports version %v. From that, the provider extracted Netbox version %v.\\nThe provider was successfully tested against the following versions:\\n\\n  %v\\n\\nUnexpected errors may occur.\", netboxVersionStringFromAPI, netboxVersion, strings.Join(supportedVersions, \", \")),\n\t\t\t})\n\t\t}\n\t}\n\n\ttags, ok := data.Get(\"default_tags\").(*schema.Set)\n\ttagCache := make(map[string]*models.NestedTag, tags.Len())\n\tif ok {\n\t\tfor _, tag := range tags.List() {\n\t\t\tif tagName, ok := tag.(string); ok {\n\t\t\t\tnbTag, err := findTag(netboxClient, tagName)\n\t\t\t\tif err != nil {\n\t\t\t\t\td := diag.FromErr(fmt.Errorf(\"default tag not found: %w\", err))\n\t\t\t\t\td[0].Severity = diag.Warning\n\t\t\t\t\tdiags = append(diags, d...)\n\t\t\t\t} else {\n\t\t\t\t\ttagCache[tagName] = nbTag\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdiags = append(diags, diag.Errorf(\"invalid type for default tag: %T\", tag)...)\n\t\t\t}\n\t\t}\n\t}\n\n\tstate := &providerState{\n\t\tNetBoxAPI:   netboxClient,\n\t\tdefaultTags: schema.CopySet(tags),\n\t\ttagCache:    tagCache,\n\t}\n\treturn state, diags\n}\n\nfunc tagsCustomDiff(ctx context.Context, diff *schema.ResourceDiff, m interface{}) error {\n\tstate := m.(*providerState)\n\n\ttagSet := diff.Get(tagsKey).(*schema.Set)\n\tallTags := tagSet.Union(state.defaultTags)\n\n\t// check if tags are already up-to-date\n\tif diff.Get(tagsAllKey).(*schema.Set).Equal(allTags) {\n\t\treturn nil // nothing to do, same set\n\t}\n\n\treturn diff.SetNew(tagsAllKey, allTags.List())\n}\n"
  },
  {
    "path": "netbox/provider_test.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nvar testAccProviders map[string]*schema.Provider\nvar testAccProvider *schema.Provider\nvar testPrefix = \"test\"\n\nfunc init() {\n\ttestAccProvider = Provider()\n\ttestAccProviders = map[string]*schema.Provider{\n\t\t\"netbox\": testAccProvider,\n\t}\n}\n\nfunc testAccGetTestName(testSlug string) string {\n\trandomString := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)\n\treturn strings.Join([]string{testPrefix, testSlug, randomString}, \"-\")\n}\n\nfunc testAccGetTestToken() string {\n\trandomToken := acctest.RandStringFromCharSet(40, \"0123456789\")\n\treturn randomToken\n}\n\nfunc testAccPreCheck(t *testing.T) {\n\tif v := os.Getenv(\"NETBOX_SERVER_URL\"); v == \"\" {\n\t\tt.Fatal(\"NETBOX_SERVER_URL must be set for acceptance tests.\")\n\t}\n\tif v := os.Getenv(\"NETBOX_API_TOKEN\"); v == \"\" {\n\t\tt.Fatal(\"NETBOX_API_TOKEN must be set for acceptance tests.\")\n\t}\n}\n\nfunc testProviderConfig(platform string) string {\n\treturn fmt.Sprintf(`\n\tresource \"netbox_platform\" \"testplatform\" {\n    name = \"%s\"\n\t}`, platform)\n}\n\nfunc providerInvalidConfigure() schema.ConfigureContextFunc {\n\treturn func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {\n\t\tvar diags diag.Diagnostics\n\n\t\tconfig := &Config{}\n\t\tconfig.ServerURL = \"https://fake.netbox.server\"\n\t\tconfig.APIToken = \"1234567890\"\n\n\t\tnetboxClient, clientError := config.Client()\n\t\tif clientError != nil {\n\t\t\treturn nil, diag.FromErr(clientError)\n\t\t}\n\n\t\treturn &providerState{NetBoxAPI: netboxClient}, diags\n\t}\n}\n\nfunc TestAccNetboxProviderConfigure_failure(t *testing.T) {\n\tvar testAccInvalidProviders map[string]*schema.Provider\n\n\ttestAccInvalidProvider := Provider()\n\ttestAccInvalidProvider.ConfigureContextFunc = providerInvalidConfigure()\n\ttestAccInvalidProviders = map[string]*schema.Provider{\n\t\t\"netbox\": testAccInvalidProvider,\n\t}\n\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccInvalidProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig:      testProviderConfig(acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)),\n\t\t\t\tExpectError: regexp.MustCompile(\"Post \\\"https://fake.netbox.server/api/dcim/platforms/\\\": dial tcp: lookup fake.netbox.server.*: no such host\"),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxProviderDefaultTags(t *testing.T) {\n\tdefaultTag := fmt.Sprintf(\"managed-%s\", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))\n\n\tresource.Test(t, resource.TestCase{\n\t\tProviderFactories: map[string]func() (*schema.Provider, error){\n\t\t\t\"netbox\": func() (*schema.Provider, error) {\n\t\t\t\tp := Provider()\n\t\t\t\tp.ConfigureContextFunc = func(ctx context.Context, rd *schema.ResourceData) (interface{}, diag.Diagnostics) {\n\t\t\t\t\trd.Set(\"default_tags\", []string{defaultTag})\n\t\t\t\t\treturn providerConfigure(ctx, rd)\n\t\t\t\t}\n\t\t\t\treturn p, nil\n\t\t\t},\n\t\t},\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\t\t\t\t\tresource \"netbox_tag\" \"managed\" {\n\t\t\t\t\t\tname = \"%s\"\n\t\t\t\t\t}\n\n\t\t\t\t\tresource \"netbox_site\" \"testsite\" {\n\t\t\t\t\t\tname = \"%s\"\n\n\t\t\t\t\t\tdepends_on = [\n\t\t\t\t\t\t\tnetbox_tag.managed\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t\t`, defaultTag, acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum),\n\t\t\t\t),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.testsite\", \"tags_all.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.testsite\", \"tags_all.0\", defaultTag),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_aggregate.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxAggregate() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxAggregateCreate,\n\t\tRead:   resourceNetboxAggregateRead,\n\t\tUpdate: resourceNetboxAggregateUpdate,\n\t\tDelete: resourceNetboxAggregateDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#aggregates):\n\n> NetBox allows us to specify the portions of IP space that are interesting to us by defining aggregates. Typically, an aggregate will correspond to either an allocation of public (globally routable) IP space granted by a regional authority, or a private (internally-routable) designation.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"prefix\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.IsCIDR,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"rir_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\nfunc resourceNetboxAggregateCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableAggregate{}\n\n\tprefix := d.Get(\"prefix\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Prefix = &prefix\n\tdata.Description = description\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\n\tif rirID, ok := d.GetOk(\"rir_id\"); ok {\n\t\tdata.Rir = int64ToPtr(int64(rirID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamAggregatesCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamAggregatesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxAggregateRead(d, m)\n}\n\nfunc resourceNetboxAggregateRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamAggregatesReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamAggregatesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamAggregatesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"description\", res.GetPayload().Description)\n\tif res.GetPayload().Prefix != nil {\n\t\td.Set(\"prefix\", res.GetPayload().Prefix)\n\t}\n\n\tif res.GetPayload().Tenant != nil {\n\t\td.Set(\"tenant_id\", res.GetPayload().Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tif res.GetPayload().Rir != nil {\n\t\td.Set(\"rir_id\", res.GetPayload().Rir.ID)\n\t} else {\n\t\td.Set(\"rir_id\", nil)\n\t}\n\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxAggregateUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableAggregate{}\n\tprefix := d.Get(\"prefix\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Prefix = &prefix\n\tdata.Description = description\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\n\tif rirID, ok := d.GetOk(\"rir_id\"); ok {\n\t\tdata.Rir = int64ToPtr(int64(rirID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamAggregatesUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Ipam.IpamAggregatesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxAggregateRead(d, m)\n}\n\nfunc resourceNetboxAggregateDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamAggregatesDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamAggregatesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamAggregatesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_aggregate_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxAggregate_basic(t *testing.T) {\n\ttestPrefix := \"1.1.1.0/25\"\n\ttestSlug := \"aggregate\"\n\ttestDesc := \"test aggregate\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_rir\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n}\nresource \"netbox_aggregate\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s\"\n  rir_id = netbox_rir.test.id\n}`, testName, randomSlug, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_aggregate.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_aggregate.test\", \"description\", testDesc),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_aggregate.test\", \"rir_id\", \"netbox_rir.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_aggregate.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_aggregate\", &resource.Sweeper{\n\t\tName:         \"netbox_aggregate\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamAggregatesListParams()\n\t\t\tres, err := api.Ipam.IpamAggregatesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, prefix := range res.GetPayload().Results {\n\t\t\t\tif len(prefix.Tags) > 0 && (prefix.Tags[0] == &models.NestedTag{Name: strToPtr(\"acctest\"), Slug: strToPtr(\"acctest\")}) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamAggregatesDeleteParams().WithID(prefix.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamAggregatesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a aggregate\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_asn.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxAsn() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxAsnCreate,\n\t\tRead:   resourceNetboxAsnRead,\n\t\tUpdate: resourceNetboxAsnUpdate,\n\t\tDelete: resourceNetboxAsnDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#asn):\n> ASN is short for Autonomous System Number. This identifier is used in the BGP protocol to identify which \"autonomous system\" a particular prefix is originating and transiting through.\n>\n> The AS number model within NetBox allows you to model some of this real-world relationship.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"asn\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: \"Value for the AS Number record\",\n\t\t\t},\n\t\t\t\"rir_id\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: \"ID for the RIR for the AS Number record\",\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"Description field for the AS Number record\",\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"Comments field for the AS Number record\",\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxAsnCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableASN{}\n\n\tasn := int64(d.Get(\"asn\").(int))\n\tdata.Asn = &asn\n\n\trir := int64(d.Get(\"rir_id\").(int))\n\tdata.Rir = &rir\n\n\tdata.Description = d.Get(\"description\").(string)\n\tdata.Comments = d.Get(\"comments\").(string)\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamAsnsCreateParams().WithData(&data)\n\n\tres, err := api.Ipam.IpamAsnsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxAsnRead(d, m)\n}\n\nfunc resourceNetboxAsnRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamAsnsReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamAsnsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamAsnsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tasn := res.GetPayload()\n\td.Set(\"asn\", asn.Asn)\n\td.Set(\"rir_id\", asn.Rir.ID)\n\td.Set(\"description\", asn.Description)\n\td.Set(\"comments\", asn.Comments)\n\tapi.readTags(d, asn.Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxAsnUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableASN{}\n\n\tasn := int64(d.Get(\"asn\").(int))\n\tdata.Asn = &asn\n\n\trir := int64(d.Get(\"rir_id\").(int))\n\tdata.Rir = &rir\n\n\tdata.Description = d.Get(\"description\").(string)\n\tdata.Comments = d.Get(\"comments\").(string)\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamAsnsUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Ipam.IpamAsnsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxAsnRead(d, m)\n}\n\nfunc resourceNetboxAsnDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamAsnsDeleteParams().WithID(id)\n\n\t_, err := api.Ipam.IpamAsnsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamAsnsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_asn_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxAsn_basic(t *testing.T) {\n\ttestSlug := \"asn_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_rir\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_asn\" \"test\" {\n  asn    = 1337\n  rir_id = netbox_rir.test.id\n\n  description = \"test\"\n  comments = \"test\"\n\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"asn\", \"1337\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"description\", \"test\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"comments\", \"test\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_asn.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\n//func TestAccNetboxAsn_customFields(t *testing.T) {\n//\ttestSlug := \"asn_detail\"\n//\ttestName := testAccGetTestName(testSlug)\n//\ttestField := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n//\tresource.Test(t, resource.TestCase{\n//\t\tPreCheck:  func() { testAccPreCheck(t) },\n//\t\tProviders: testAccProviders,\n//\t\tSteps: []resource.TestStep{\n//\t\t\t{\n//\t\t\t\tConfig: fmt.Sprintf(`\n//resource \"netbox_custom_field\" \"test\" {\n//\tname          = \"%[1]s\"\n//\ttype          = \"text\"\n//\tcontent_types = [\"ipam.asn\"]\n//}\n//resource \"netbox_asn\" \"test\" {\n//  name          = \"%[2]s\"\n//  status        = \"active\"\n//  latitude      = \"12.123456\"\n//  longitude     = \"-13.123456\"\n//  timezone      = \"Africa/Johannesburg\"\n//  custom_fields = {\"${netbox_custom_field.test.name}\" = \"81\"}\n//}`, testField, testName),\n//\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n//\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"custom_fields.\"+testField, \"81\"),\n//\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"timezone\", \"Africa/Johannesburg\"),\n//\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"latitude\", \"12.123456\"),\n//\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_asn.test\", \"longitude\", \"-13.123456\"),\n//\t\t\t\t),\n//\t\t\t},\n//\t\t},\n//\t})\n//}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_asn\", &resource.Sweeper{\n\t\tName:         \"netbox_asn\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamAsnsListParams()\n\t\t\tres, err := api.Ipam.IpamAsnsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, asn := range res.GetPayload().Results {\n\t\t\t\tdeleteParams := ipam.NewIpamAsnsDeleteParams().WithID(asn.ID)\n\t\t\t\t_, err := api.Ipam.IpamAsnsDelete(deleteParams, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tlog.Print(\"[DEBUG] Deleted an asn\")\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_available_ip_address.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxAvailableIPAddress() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxAvailableIPAddressCreate,\n\t\tRead:   resourceNetboxAvailableIPAddressRead,\n\t\tUpdate: resourceNetboxAvailableIPAddressUpdate,\n\t\tDelete: resourceNetboxAvailableIPAddressDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):Per [the docs](https://netbox.readthedocs.io/en/stable/models/ipam/ipaddress/):\n\n> An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.\n> Like a prefix, an IP address can optionally be assigned to a VRF (otherwise, it will appear in the \"global\" table). IP addresses are automatically arranged under parent prefixes within their respective VRFs according to the IP hierarchya.\n>\n> Each IP address can also be assigned an operational status and a functional role. Statuses are hard-coded in NetBox and include the following:\n> * Active\n> * Reserved\n> * Deprecated\n> * DHCP\n> * SLAAC (IPv6 Stateless Address Autoconfiguration)\n\nThis resource will retrieve the next available IP address from a given prefix or IP range (specified by ID)`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"prefix_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tForceNew:     true,\n\t\t\t\tExactlyOneOf: []string{\"prefix_id\", \"ip_range_id\"},\n\t\t\t},\n\t\t\t\"ip_range_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tForceNew:     true,\n\t\t\t\tExactlyOneOf: []string{\"prefix_id\", \"ip_range_id\"},\n\t\t\t},\n\t\t\t\"ip_address\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"interface_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"object_type\"},\n\t\t\t},\n\t\t\t\"object_type\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxIPAddressObjectTypeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxIPAddressObjectTypeOptions),\n\t\t\t\tRequiredWith: []string{\"interface_id\"},\n\t\t\t},\n\t\t\t\"virtual_machine_interface_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"interface_id\", \"device_interface_id\"},\n\t\t\t},\n\t\t\t\"device_interface_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"interface_id\", \"virtual_machine_interface_id\"},\n\t\t\t},\n\t\t\t\"vrf_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxIPAddressStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxIPAddressStatusOptions),\n\t\t\t\tDefault:      \"active\",\n\t\t\t},\n\t\t\t\"dns_name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\t// NetBox always converts DNS names to lowercase\n\t\t\t\tDiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {\n\t\t\t\t\treturn strings.EqualFold(old, new)\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"role\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxIPAddressRoleOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxIPAddressRoleOptions),\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxAvailableIPAddressCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tprefixID := int64(d.Get(\"prefix_id\").(int))\n\tvrfID := int64(int64(d.Get(\"vrf_id\").(int)))\n\trangeID := int64(d.Get(\"ip_range_id\").(int))\n\tnestedvrf := models.NestedVRF{\n\t\tID: vrfID,\n\t}\n\tdata := models.AvailableIP{\n\t\tVrf: &nestedvrf,\n\t}\n\tif prefixID != 0 {\n\t\tparams := ipam.NewIpamPrefixesAvailableIpsCreateParams().WithID(prefixID).WithData([]*models.AvailableIP{&data})\n\t\tres, err := api.Ipam.IpamPrefixesAvailableIpsCreate(params, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(res.Payload) == 0 {\n\t\t\treturn fmt.Errorf(\"no available IP addresses in prefix %d\", prefixID)\n\t\t}\n\t\t// Since we generated the ip_address, set that now\n\t\td.SetId(strconv.FormatInt(res.Payload[0].ID, 10))\n\t\td.Set(\"ip_address\", *res.Payload[0].Address)\n\t}\n\tif rangeID != 0 {\n\t\tparams := ipam.NewIpamIPRangesAvailableIpsCreateParams().WithID(rangeID).WithData([]*models.AvailableIP{&data})\n\t\tres, err := api.Ipam.IpamIPRangesAvailableIpsCreate(params, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(res.Payload) == 0 {\n\t\t\treturn fmt.Errorf(\"no available IP addresses in IP range %d\", rangeID)\n\t\t}\n\t\t// Since we generated the ip_address, set that now\n\t\td.SetId(strconv.FormatInt(res.Payload[0].ID, 10))\n\t\td.Set(\"ip_address\", *res.Payload[0].Address)\n\t}\n\treturn resourceNetboxAvailableIPAddressUpdate(d, m)\n}\n\nfunc resourceNetboxAvailableIPAddressRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamIPAddressesReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamIPAddressesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamIPAddressesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tipAddress := res.GetPayload()\n\tif ipAddress.AssignedObjectID != nil {\n\t\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\t\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\t\tinterfaceID := getOptionalInt(d, \"interface_id\")\n\n\t\tswitch {\n\t\tcase vmInterfaceID != nil:\n\t\t\td.Set(\"virtual_machine_interface_id\", ipAddress.AssignedObjectID)\n\t\tcase deviceInterfaceID != nil:\n\t\t\td.Set(\"device_interface_id\", ipAddress.AssignedObjectID)\n\t\t// if interfaceID is given, object_type must be set as well\n\t\tcase interfaceID != nil:\n\t\t\td.Set(\"object_type\", ipAddress.AssignedObjectType)\n\t\t\td.Set(\"interface_id\", ipAddress.AssignedObjectID)\n\t\t}\n\t} else {\n\t\td.Set(\"interface_id\", nil)\n\t\td.Set(\"object_type\", \"\")\n\t}\n\n\tif ipAddress.Vrf != nil {\n\t\td.Set(\"vrf_id\", ipAddress.Vrf.ID)\n\t} else {\n\t\td.Set(\"vrf_id\", nil)\n\t}\n\n\tif ipAddress.Tenant != nil {\n\t\td.Set(\"tenant_id\", ipAddress.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tif ipAddress.DNSName != \"\" {\n\t\td.Set(\"dns_name\", ipAddress.DNSName)\n\t}\n\n\td.Set(\"ip_address\", ipAddress.Address)\n\td.Set(\"description\", ipAddress.Description)\n\td.Set(\"status\", ipAddress.Status.Value)\n\tapi.readTags(d, ipAddress.Tags)\n\tcf := getCustomFields(ipAddress.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\treturn nil\n}\n\nfunc resourceNetboxAvailableIPAddressUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableIPAddress{}\n\n\tdata.Address = strToPtr(d.Get(\"ip_address\").(string))\n\tdata.Status = d.Get(\"status\").(string)\n\n\tdata.Description = getOptionalStr(d, \"description\", false)\n\tdata.Role = getOptionalStr(d, \"role\", false)\n\tdata.DNSName = getOptionalStr(d, \"dns_name\", false)\n\tdata.Vrf = getOptionalInt(d, \"vrf_id\")\n\tdata.Tenant = getOptionalInt(d, \"tenant_id\")\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tif interfaceID, ok := d.GetOk(\"interface_id\"); ok {\n\t\t// The other possible type is dcim.interface for devices\n\t\tdata.AssignedObjectType = strToPtr(\"virtualization.vminterface\")\n\t\tdata.AssignedObjectID = int64ToPtr(int64(interfaceID.(int)))\n\t}\n\n\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\tinterfaceID := getOptionalInt(d, \"interface_id\")\n\n\tswitch {\n\tcase vmInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"virtualization.vminterface\")\n\t\tdata.AssignedObjectID = vmInterfaceID\n\tcase deviceInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"dcim.interface\")\n\t\tdata.AssignedObjectID = deviceInterfaceID\n\t// if interfaceID is given, object_type must be set as well\n\tcase interfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(d.Get(\"object_type\").(string))\n\t\tdata.AssignedObjectID = interfaceID\n\t// default = ip is not linked to anything\n\tdefault:\n\t\tdata.AssignedObjectType = strToPtr(\"\")\n\t\tdata.AssignedObjectID = nil\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamIPAddressesUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Ipam.IpamIPAddressesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxAvailableIPAddressRead(d, m)\n}\n\nfunc resourceNetboxAvailableIPAddressDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamIPAddressesDeleteParams().WithID(id)\n\n\t_, err := api.Ipam.IpamIPAddressesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamIPAddressesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_available_ip_address_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxAvailableIPAddress_basic(t *testing.T) {\n\ttestPrefix := \"1.1.2.0/24\"\n\ttestIP := \"1.1.2.1/24\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  status = \"active\"\n  is_pool = false\n}\nresource \"netbox_available_ip_address\" \"test\" {\n  prefix_id = netbox_prefix.test.id\n  status = \"active\"\n  dns_name = \"test.mydomain.local\"\n  role = \"loopback\"\n}`, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", \"dns_name\", \"test.mydomain.local\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", \"role\", \"loopback\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\nfunc TestAccNetboxAvailableIPAddress_basic_range(t *testing.T) {\n\tstartAddress := \"1.1.5.1/24\"\n\tendAddress := \"1.1.5.50/24\"\n\ttestIP := \"1.1.5.1/24\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n}\nresource \"netbox_available_ip_address\" \"test_range\" {\n  ip_range_id = netbox_ip_range.test.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n}`, startAddress, endAddress),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test_range\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test_range\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test_range\", \"dns_name\", \"test_range.mydomain.local\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailableIPAddress_multipleIpsParallel(t *testing.T) {\n\ttestPrefix := \"1.1.3.0/24\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  status = \"active\"\n  is_pool = false\n}\nresource \"netbox_available_ip_address\" \"test1\" {\n  prefix_id = netbox_prefix.test.id\n  status = \"active\"\n  dns_name = \"test.mydomain.local\"\n}\nresource \"netbox_available_ip_address\" \"test2\" {\n  prefix_id = netbox_prefix.test.id\n  status = \"active\"\n  dns_name = \"test.mydomain.local\"\n}\nresource \"netbox_available_ip_address\" \"test3\" {\n  prefix_id = netbox_prefix.test.id\n  status = \"active\"\n  dns_name = \"test.mydomain.local\"\n}`, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_ip_address.test1\", \"ip_address\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_ip_address.test2\", \"ip_address\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_ip_address.test3\", \"ip_address\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailableIPAddress_multipleIpsParallel_range(t *testing.T) {\n\tstartAddress := \"1.1.6.1/24\"\n\tendAddress := \"1.1.6.50/24\"\n\ttestIP := []string{\"1.1.6.1/24\", \"1.1.6.2/24\", \"1.1.6.3/24\"}\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test_range\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n}\nresource \"netbox_available_ip_address\" \"test_range1\" {\n  ip_range_id = test_range.test_range.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n}\nresource \"netbox_available_ip_address\" \"test_range2\" {\n  ip_range_id = test_range.test_range.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n}\nresource \"netbox_available_ip_address\" \"test_range3\" {\n  ip_range_id = test_range.test_range.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n}`, startAddress, endAddress),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test1\", \"ip_address\", testIP[0]),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test2\", \"ip_address\", testIP[1]),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test3\", \"ip_address\", testIP[2]),\n\t\t\t\t),\n\t\t\t\tExpectError: regexp.MustCompile(\".*\"),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailableIPAddress_multipleIpsSerial(t *testing.T) {\n\ttestPrefix := \"1.1.4.0/24\"\n\ttestIP := []string{\"1.1.4.1/24\", \"1.1.4.2/24\", \"1.1.4.3/24\"}\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  status = \"active\"\n  is_pool = false\n}\nresource \"netbox_available_ip_address\" \"test1\" {\n  prefix_id = netbox_prefix.test.id\n  status = \"active\"\n  dns_name = \"test.mydomain.local\"\n}\nresource \"netbox_available_ip_address\" \"test2\" {\n  depends_on = [netbox_available_ip_address.test1]\n  prefix_id = netbox_prefix.test.id\n  status = \"active\"\n  dns_name = \"test.mydomain.local\"\n}\nresource \"netbox_available_ip_address\" \"test3\" {\n  depends_on = [netbox_available_ip_address.test2]\n  prefix_id = netbox_prefix.test.id\n  status = \"active\"\n  dns_name = \"test.mydomain.local\"\n}`, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test1\", \"ip_address\", testIP[0]),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test2\", \"ip_address\", testIP[1]),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test3\", \"ip_address\", testIP[2]),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailableIPAddress_multipleIpsSerial_range(t *testing.T) {\n\tstartAddress := \"1.1.7.1/24\"\n\tendAddress := \"1.1.7.50/24\"\n\ttestIP := []string{\"1.1.7.1/24\", \"1.1.7.2/24\", \"1.1.7.3/24\"}\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test_range\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n}\nresource \"netbox_available_ip_address\" \"test_range1\" {\n  ip_range_id = netbox_ip_range.test_range.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n}\nresource \"netbox_available_ip_address\" \"test_range2\" {\n  depends_on = [netbox_available_ip_address.test_range1]\n  ip_range_id = netbox_ip_range.test_range.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n}\nresource \"netbox_available_ip_address\" \"test_range3\" {\n  depends_on = [netbox_available_ip_address.test_range2]\n  ip_range_id = netbox_ip_range.test_range.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n}`, startAddress, endAddress),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test_range1\", \"ip_address\", testIP[0]),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test_range2\", \"ip_address\", testIP[1]),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test_range3\", \"ip_address\", testIP[2]),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailableIPAddress_deviceByObjectType(t *testing.T) {\n\tstartAddress := \"1.2.7.1/24\"\n\tendAddress := \"1.2.7.50/24\"\n\ttestSlug := \"av_ipa_dev_ot\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDeviceDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test_range\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n}\nresource \"netbox_available_ip_address\" \"test\" {\n  ip_range_id = netbox_ip_range.test_range.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n  object_type = \"dcim.interface\"\n  interface_id = netbox_device_interface.test.id\n}`, startAddress, endAddress),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", \"object_type\", \"dcim.interface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_available_ip_address.test\", \"interface_id\", \"netbox_device_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailableIPAddress_deviceByFieldName(t *testing.T) {\n\tstartAddress := \"1.3.7.1/24\"\n\tendAddress := \"1.3.7.50/24\"\n\ttestSlug := \"av_ipa_dev_fn\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDeviceDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test_range\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n}\nresource \"netbox_available_ip_address\" \"test\" {\n  ip_range_id = netbox_ip_range.test_range.id\n  status = \"active\"\n  dns_name = \"test_range.mydomain.local\"\n  device_interface_id = netbox_device_interface.test.id\n}`, startAddress, endAddress),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_available_ip_address.test\", \"device_interface_id\", \"netbox_device_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailableIPAddress_cf(t *testing.T) {\n\ttestPrefix := \"1.1.8.0/24\"\n\ttestIP := \"1.1.8.1/24\"\n\ttestSlug := \"av_ipa_cf\"\n\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name   = \"%s\"\n  type   = \"text\"\n  weight = 100\n  content_types = [\"ipam.ipaddress\"]\n}\n\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  status = \"active\"\n  is_pool = false\n}\n\nresource \"netbox_available_ip_address\" \"test\" {\n  prefix_id = netbox_prefix.test.id\n  status = \"active\"\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"test-field\"\n  }\n}`, testSlug, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_ip_address.test\", fmt.Sprintf(\"custom_fields.%s\", testSlug), \"test-field\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_available_ip_address.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t\tImportStateVerifyIgnore: []string{\n\t\t\t\t\t\"prefix_id\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_available_ip_address\", &resource.Sweeper{\n\t\tName:         \"netbox_available_ip_address\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamIPAddressesListParams()\n\t\t\tres, err := api.Ipam.IpamIPAddressesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, ipAddress := range res.GetPayload().Results {\n\t\t\t\tif len(ipAddress.Tags) > 0 && (ipAddress.Tags[0] == &models.NestedTag{Name: strToPtr(\"acctest\"), Slug: strToPtr(\"acctest\")}) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamIPAddressesDeleteParams().WithID(ipAddress.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamIPAddressesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted an ip address\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_available_prefix.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxAvailablePrefix() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxAvailablePrefixCreate,\n\t\tRead:   resourceNetboxPrefixRead,\n\t\tUpdate: resourceNetboxPrefixUpdate,\n\t\tDelete: resourceNetboxPrefixDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"parent_prefix_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t\tForceNew: true,\n\t\t\t},\n\t\t\t\"prefix_length\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tRequired:     true,\n\t\t\t\tForceNew:     true,\n\t\t\t\tValidateFunc: validation.IntBetween(0, 128),\n\t\t\t},\n\t\t\t\"prefix\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxPrefixStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxPrefixStatusOptions),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"is_pool\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_utilized\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"vrf_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"site_id\", \"site_group_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_group_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"site_group_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"region_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_id\", \"site_group_id\"},\n\t\t\t},\n\t\t\t\"vlan_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t\ttagsKey:         tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: func(c context.Context, rd *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {\n\t\t\t\tparentPrefixID, prefixID, prefixLength, err := resourceNetboxAvailablePrefixParseImport(rd.Id())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\trd.Set(\"parent_prefix_id\", parentPrefixID)\n\t\t\t\trd.Set(\"prefix_length\", prefixLength)\n\t\t\t\trd.SetId(prefixID)\n\n\t\t\t\treturn []*schema.ResourceData{rd}, nil\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc resourceNetboxAvailablePrefixParseImport(importStr string) (int, string, int, error) {\n\tparts := strings.SplitN(importStr, \" \", 3)\n\n\tif len(parts) != 3 || parts[0] == \"\" || parts[1] == \"\" || parts[2] == \"\" {\n\t\treturn 0, \"\", 0, fmt.Errorf(\"unexpected format of (%s), expected 'parent_prefix_id prefix_id prefix_length'\", importStr)\n\t}\n\n\tparentID, err := strconv.Atoi(parts[0])\n\tif err != nil {\n\t\treturn 0, \"\", 0, fmt.Errorf(\"parent_id (%s) is not an integer\", parts[0])\n\t}\n\tprefixLength, err := strconv.Atoi(parts[2])\n\tif err != nil {\n\t\treturn 0, \"\", 0, fmt.Errorf(\"prefix_length (%s) is not an integer\", parts[1])\n\t}\n\n\treturn parentID, parts[1], prefixLength, nil\n}\n\nfunc resourceNetboxAvailablePrefixCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tparentPrefixID := int64(d.Get(\"parent_prefix_id\").(int))\n\tprefixLength := int64(d.Get(\"prefix_length\").(int))\n\tdata := models.PrefixLength{\n\t\tPrefixLength: &prefixLength,\n\t}\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\tparams := ipam.NewIpamPrefixesAvailablePrefixesCreateParams().WithID(parentPrefixID).WithData(&data)\n\n\tres, err := api.Ipam.IpamPrefixesAvailablePrefixesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpayload := res.GetPayload()\n\td.SetId(strconv.FormatInt(payload.ID, 10))\n\td.Set(\"prefix\", payload.Prefix)\n\n\treturn resourceNetboxPrefixUpdate(d, m)\n}\n"
  },
  {
    "path": "netbox/resource_netbox_available_prefix_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxAvailablePrefixFullDependencies(testName string, parentPrefix string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_prefix\" \"parent\" {\n  prefix = \"%[2]s\"\n  description = \"%[1]s\"\n  status = \"container\"\n  tags = [netbox_tag.test.name]\n  lifecycle {\n    ignore_changes = [%[3]s]\n  }\n}\n`, testName, parentPrefix, customFieldsKey)\n}\n\nfunc TestAccNetboxAvailablePrefix_basic(t *testing.T) {\n\ttestParentPrefix := \"1.1.0.0/24\"\n\ttestPrefixLength := 25\n\texpectedPrefix := \"1.1.0.0/25\"\n\ttestSlug := \"prefix\"\n\ttestDesc := \"test prefix\"\n\ttestName := testAccGetTestName(testSlug)\n\n\tparentResourceName := \"netbox_prefix.parent\"\n\tresourceName := \"netbox_available_prefix.test\"\n\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + fmt.Sprintf(`\nresource \"netbox_available_prefix\" \"test\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %d\n  description = \"%s\"\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n  mark_utilized = true\n  is_pool = true\n}`, testPrefixLength, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"prefix\", expectedPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"description\", testDesc),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"mark_utilized\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"is_pool\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + fmt.Sprintf(`\nresource \"netbox_available_prefix\" \"test\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %d\n  description = \"%s\"\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n  mark_utilized = false\n  is_pool = false\n}`, testPrefixLength, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"mark_utilized\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"is_pool\", \"false\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      resourceName,\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t\tImportStateIdFunc: func(s *terraform.State) (string, error) {\n\t\t\t\t\tparent, ok := s.RootModule().Resources[parentResourceName]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn \"\", fmt.Errorf(\"Not found: %s\", parentResourceName)\n\t\t\t\t\t}\n\t\t\t\t\tresource, ok := s.RootModule().Resources[resourceName]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn \"\", fmt.Errorf(\"Not found: %s\", resourceName)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn fmt.Sprintf(\"%s %s %d\", parent.Primary.ID, resource.Primary.ID, testPrefixLength), nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailablePrefix_cf(t *testing.T) {\n\ttestParentPrefix := \"1.1.0.0/24\"\n\ttestPrefixLength := 25\n\texpectedPrefix := \"1.1.0.0/25\"\n\ttestSlug := \"prefix_cf\"\n\ttestName := testAccGetTestName(testSlug)\n\n\tparentResourceName := \"netbox_prefix.parent\"\n\tresourceName := \"netbox_available_prefix.test\"\n\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name   = \"%s\"\n  type   = \"text\"\n  weight = 100\n  content_types = [\"ipam.prefix\"]\n}\n\nresource \"netbox_available_prefix\" \"test\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %d\n  status = \"active\"\n\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"test-field\"\n  }\n}`, testSlug, testPrefixLength),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"prefix\", expectedPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(resourceName, fmt.Sprintf(\"custom_fields.%s\", testSlug), \"test-field\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      resourceName,\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t\tImportStateIdFunc: func(s *terraform.State) (string, error) {\n\t\t\t\t\tparent, ok := s.RootModule().Resources[parentResourceName]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn \"\", fmt.Errorf(\"Not found: %s\", parentResourceName)\n\t\t\t\t\t}\n\t\t\t\t\tresource, ok := s.RootModule().Resources[resourceName]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn \"\", fmt.Errorf(\"Not found: %s\", resourceName)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn fmt.Sprintf(\"%s %s %d\", parent.Primary.ID, resource.Primary.ID, testPrefixLength), nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxAvailablePrefix_multiplePrefixesSerial(t *testing.T) {\n\ttestParentPrefix := \"1.1.0.0/24\"\n\ttestPrefixLength := 25\n\texpectedPrefixes := []string{\n\t\t\"1.1.0.0/25\",\n\t\t\"1.1.0.128/25\",\n\t}\n\ttestSlug := \"prefix\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + fmt.Sprintf(`\nresource \"netbox_available_prefix\" \"test1\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %d\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\nresource \"netbox_available_prefix\" \"test2\" {\n  depends_on = [netbox_available_prefix.test1]\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = netbox_available_prefix.test1.prefix_length\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\n`, testPrefixLength),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_prefix.test1\", \"prefix\", expectedPrefixes[0]),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_prefix.test2\", \"prefix\", expectedPrefixes[1]),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + fmt.Sprintf(`\nresource \"netbox_available_prefix\" \"test1\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %d\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\nresource \"netbox_available_prefix\" \"test2\" {\n  depends_on = [netbox_available_prefix.test1]\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = netbox_available_prefix.test1.prefix_length\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\nresource \"netbox_available_prefix\" \"test3\" {\n  depends_on = [netbox_available_prefix.test2]\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = netbox_available_prefix.test1.prefix_length\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}\n`, testPrefixLength),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_prefix.test1\", \"prefix\", expectedPrefixes[0]),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_prefix.test2\", \"prefix\", expectedPrefixes[1]),\n\t\t\t\t),\n\t\t\t\tExpectError: regexp.MustCompile(\".*Insufficient resources are available to satisfy the request.*\"),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxAvailablePrefixScopeDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_region\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site_group\" \"test\" {\n  name = \"%[1]s\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxAvailablePrefix_scopes(t *testing.T) {\n\ttestParentPrefix := \"16.1.0.0/24\"\n\ttestPrefixLength := 25\n\ttestSlug := \"prefix-scopes\"\n\ttestName := testAccGetTestName(testSlug)\n\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + testAccNetboxAvailablePrefixScopeDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_available_prefix\" \"with_site_id\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %[2]d\n  status = \"active\"\n  site_id = netbox_site.test.id\n}`, testSlug, testPrefixLength),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_available_prefix.with_site_id\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + testAccNetboxAvailablePrefixScopeDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_available_prefix\" \"with_location_id\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %[2]d\n  status = \"active\"\n  location_id = netbox_location.test.id\n}`, testSlug, testPrefixLength),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_available_prefix.with_location_id\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + testAccNetboxAvailablePrefixScopeDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_available_prefix\" \"with_region_id\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %[2]d\n  status = \"active\"\n  region_id = netbox_region.test.id\n}`, testSlug, testPrefixLength),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_available_prefix.with_region_id\", \"region_id\", \"netbox_region.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxAvailablePrefixFullDependencies(testName, testParentPrefix) + testAccNetboxAvailablePrefixScopeDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_available_prefix\" \"with_site_group_id\" {\n  parent_prefix_id = netbox_prefix.parent.id\n  prefix_length = %[2]d\n  status = \"active\"\n  site_group_id = netbox_site_group.test.id\n}`, testSlug, testPrefixLength),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_available_prefix.with_site_group_id\", \"site_group_id\", \"netbox_site_group.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_available_prefix\", &resource.Sweeper{\n\t\tName:         \"netbox_available_prefix\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamPrefixesListParams()\n\t\t\tres, err := api.Ipam.IpamPrefixesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, prefix := range res.GetPayload().Results {\n\t\t\t\tif len(prefix.Tags) > 0 && (prefix.Tags[0] == &models.NestedTag{Name: strToPtr(\"acctest\"), Slug: strToPtr(\"acctest\")}) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamPrefixesDeleteParams().WithID(prefix.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamPrefixesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a prefix\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_available_vlan.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxAvailableVLAN() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxAvailableVLANCreate,\n\t\tRead:   resourceNetboxAvailableVLANRead,\n\t\tUpdate: resourceNetboxAvailableVLANUpdate,\n\t\tDelete: resourceNetboxAvailableVLANDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):Per [the docs](https://netbox.readthedocs.io/en/stable/models/ipam/vlan/):\n\n> A VLAN represents an isolated Layer 2 domain identified by a numeric ID (1–4094). VLANs may be assigned to specific sites or marked as global.\n> Optionally, they can be organized within VLAN groups to define scope and enforce uniqueness.\n>\n> Each VLAN can also be assigned an operational status and a functional role. Statuses are hard-coded in NetBox and include the following:\n> * Active\n> * Reserved\n> * Deprecated\n\nThis resource will retrieve the next available VLAN ID from a given VLAN group (specified by ID).`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"vid\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true, // it's auto-assigned by NetBox, not user-supplied\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxAvailableVLANCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tgroupID := int64(d.Get(\"group_id\").(int))\n\n\ttags, err := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdata := &models.WritableCreateAvailableVLAN{\n\t\tName:        strToPtr(d.Get(\"name\").(string)),\n\t\tDescription: getOptionalStr(d, \"description\", false),\n\t\tTenant:      getOptionalInt(d, \"tenant_id\"),\n\t\tSite:        getOptionalInt(d, \"site_id\"),\n\t\tRole:        getOptionalInt(d, \"role_id\"),\n\t\tStatus:      d.Get(\"status\").(string),\n\t\tTags:        tags,\n\t}\n\n\tparams := ipam.NewIpamVlanGroupsAvailableVlansCreateParams().WithID(groupID).WithData(data)\n\tresp, err := api.Ipam.IpamVlanGroupsAvailableVlansCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvlan := resp.Payload\n\td.SetId(strconv.FormatInt(vlan.ID, 10))\n\td.Set(\"vid\", vlan.Vid)\n\td.Set(\"name\", vlan.Name)\n\td.Set(\"group_id\", vlan.Group.ID)\n\treturn resourceNetboxAvailableVLANRead(d, m)\n}\n\nfunc resourceNetboxAvailableVLANRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamVlansReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamVlansRead(params, nil)\n\tif err != nil {\n\t\tif erresp, ok := err.(*ipam.IpamVlansReadDefault); ok {\n\t\t\terrorcode := erresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tvlan := res.GetPayload()\n\t// Required fields\n\td.Set(\"vid\", vlan.Vid)\n\td.Set(\"name\", vlan.Name)\n\n\t// Optional fields\n\td.Set(\"description\", vlan.Description)\n\td.Set(\"comments\", vlan.Comments)\n\n\tif vlan.Status != nil && vlan.Status.Value != nil {\n\t\td.Set(\"status\", *vlan.Status.Value)\n\t} else {\n\t\td.Set(\"status\", \"\")\n\t}\n\n\tif vlan.Tenant != nil {\n\t\td.Set(\"tenant_id\", vlan.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tif vlan.Site != nil {\n\t\td.Set(\"site_id\", vlan.Site.ID)\n\t} else {\n\t\td.Set(\"site_id\", nil)\n\t}\n\n\tif vlan.Group != nil {\n\t\td.Set(\"group_id\", vlan.Group.ID)\n\t} else {\n\t\td.Set(\"group_id\", nil)\n\t}\n\n\tif vlan.Role != nil {\n\t\td.Set(\"role_id\", vlan.Role.ID)\n\t} else {\n\t\td.Set(\"role_id\", nil)\n\t}\n\n\tapi.readTags(d, vlan.Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxAvailableVLANUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := &models.WritableVLAN{\n\t\tName:        strToPtr(d.Get(\"name\").(string)),\n\t\tDescription: getOptionalStr(d, \"description\", false),\n\t\tTenant:      getOptionalInt(d, \"tenant_id\"),\n\t\tSite:        getOptionalInt(d, \"site_id\"),\n\t\tGroup:       getOptionalInt(d, \"group_id\"),\n\t\tRole:        getOptionalInt(d, \"role_id\"),\n\t\tStatus:      d.Get(\"status\").(string),\n\t\tVid:         int64ToPtr(int64(d.Get(\"vid\").(int))),\n\t}\n\n\tvar err_tags error\n\tdata.Tags, err_tags = getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))\n\tif err_tags != nil {\n\t\treturn err_tags\n\t}\n\n\tparams := ipam.NewIpamVlansUpdateParams().\n\t\tWithID(id).\n\t\tWithData(data)\n\n\t_, err := api.Ipam.IpamVlansUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxAvailableVLANRead(d, m)\n}\n\nfunc resourceNetboxAvailableVLANDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := ipam.NewIpamVlansDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamVlansDelete(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamVlansDeleteDefault); ok && errresp.Code() == 404 {\n\t\t\td.SetId(\"\")\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_available_vlan_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\n// TestAccNetboxAvailableVLAN_basic verifies that a basic available VLAN can be\n// created in NetBox using a VLAN group and a site. It ensures required attributes\n// like name, status, and vid are correctly set and persisted.\nfunc TestAccNetboxAvailableVLAN_basic(t *testing.T) {\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: `\nresource \"netbox_site\" \"test_site\" {\n  name = \"testSite\"\n  slug = \"ts\"\n}\n\nresource \"netbox_vlan_group\" \"groupTest\" {\n  name        = \"Group Test\"\n  slug        = \"group-test\"\n  scope_id    = netbox_site.test_site.id\n  scope_type  = \"dcim.site\"\n  description = \"First VLAN group\"\n  vid_ranges  = [[1,20]]\n}\n\nresource \"netbox_available_vlan\" \"vlanTest\" {\n  name        = \"test-vlan\"\n  status      = \"active\"\n  description = \"Virtual network for testing purposes\"\n  group_id    = netbox_vlan_group.groupTest.id\n  site_id     = netbox_vlan_group.groupTest.scope_id\n}\n`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_vlan.vlanTest\", \"name\", \"test-vlan\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_available_vlan.vlanTest\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlanTest\", \"vid\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlanTest\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlanTest\", \"group_id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxAvailableVLAN_basic_range ensures that the VLAN created by the\n// provider has a VID that falls within the specified vid_ranges of the group.\nfunc TestAccNetboxAvailableVLAN_basic_range(t *testing.T) {\n\tconst (\n\t\tminVID = 10\n\t\tmaxVID = 20\n\t)\n\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test_site\" {\n  name = \"Test Site\"\n  slug = \"test-site\"\n}\n\nresource \"netbox_vlan_group\" \"group1\" {\n  name        = \"Group One\"\n  slug        = \"group-one\"\n  scope_id    = netbox_site.test_site.id\n  scope_type  = \"dcim.site\"\n  description = \"First VLAN group\"\n  vid_ranges  = [[%d, %d]]\n}\n\nresource \"netbox_available_vlan\" \"vlan_test\" {\n  name        = \"test-vlan\"\n  status      = \"active\"\n  group_id    = netbox_vlan_group.group1.id\n  site_id     = netbox_vlan_group.group1.scope_id\n  description = \"Autogenerated VLAN\"\n}\n`, minVID, maxVID),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan_test\", \"vid\"),\n\t\t\t\t\tfunc(s *terraform.State) error {\n\t\t\t\t\t\trs, ok := s.RootModule().Resources[\"netbox_available_vlan.vlan_test\"]\n\t\t\t\t\t\tif !ok {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"not found: netbox_available_vlan.vlan_test\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvidStr := rs.Primary.Attributes[\"vid\"]\n\t\t\t\t\t\tvid, err := strconv.Atoi(vidStr)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"invalid vid: %s\", vidStr)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif vid < minVID || vid > maxVID {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"vid %d is out of expected range [%d-%d]\", vid, minVID, maxVID)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxAvailableVLAN_multipleSerial checks that multiple available VLANs\n// can be allocated serially from the same VLAN group.\nfunc TestAccNetboxAvailableVLAN_multipleSerial(t *testing.T) {\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: `\nresource \"netbox_site\" \"test_site\" {\n  name = \"Serial Test Site\"\n  slug = \"serial-test-site\"\n}\n\nresource \"netbox_vlan_group\" \"group2\" {\n  name        = \"Group Two\"\n  slug        = \"group-two\"\n  scope_id    = netbox_site.test_site.id\n  scope_type  = \"dcim.site\"\n  vid_ranges  = [[30, 32]]\n}\n\nresource \"netbox_available_vlan\" \"vlan1\" {\n  name     = \"vlan-1\"\n  status   = \"active\"\n  group_id = netbox_vlan_group.group2.id\n  site_id  = netbox_vlan_group.group2.scope_id\n}\n\nresource \"netbox_available_vlan\" \"vlan2\" {\n  depends_on = [netbox_available_vlan.vlan1]\n  name     = \"vlan-2\"\n  status   = \"active\"\n  group_id = netbox_vlan_group.group2.id\n  site_id  = netbox_vlan_group.group2.scope_id\n}\n`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan1\", \"vid\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan2\", \"vid\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxAvailableVLAN_multipleSerial_range validates that sequential allocation\n// works correctly when a VLAN group has multiple vid_ranges. Here it confirms it by\n// verifying that third vlan falls in the second range of available ids.\nfunc TestAccNetboxAvailableVLAN_multipleSerial_range(t *testing.T) {\n\tconst (\n\t\tminVID1 = 1\n\t\tmaxVID1 = 2\n\t\tminVID2 = 7\n\t\tmaxVID2 = 17\n\t)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test_site\" {\n  name = \"Serial Test range Site\"\n  slug = \"serial-test-range-site\"\n}\n\nresource \"netbox_vlan_group\" \"group2\" {\n  name        = \"Group Two\"\n  slug        = \"group-two\"\n  scope_id    = netbox_site.test_site.id\n  scope_type  = \"dcim.site\"\n  vid_ranges  = [[%d, %d], [%d,%d]]\n}\n\nresource \"netbox_available_vlan\" \"vlan1\" {\n  name     = \"vlan-1\"\n  status   = \"active\"\n  group_id = netbox_vlan_group.group2.id\n  site_id  = netbox_vlan_group.group2.scope_id\n}\n\nresource \"netbox_available_vlan\" \"vlan2\" {\n  depends_on = [netbox_available_vlan.vlan1]\n  name     = \"vlan-2\"\n  status   = \"active\"\n  group_id = netbox_vlan_group.group2.id\n  site_id  = netbox_vlan_group.group2.scope_id\n}\n\nresource \"netbox_available_vlan\" \"vlan3\" {\n  depends_on = [netbox_available_vlan.vlan2]\n  name     = \"vlan-3\"\n  status   = \"active\"\n  group_id = netbox_vlan_group.group2.id\n  site_id  = netbox_vlan_group.group2.scope_id\n}\n`, minVID1, maxVID1, minVID2, maxVID2),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan1\", \"vid\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan2\", \"vid\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan3\", \"vid\"),\n\t\t\t\t\tfunc(s *terraform.State) error {\n\t\t\t\t\t\trs, ok := s.RootModule().Resources[\"netbox_available_vlan.vlan3\"]\n\t\t\t\t\t\tif !ok {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"not found: netbox_available_vlan.vlan3\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvidStr := rs.Primary.Attributes[\"vid\"]\n\t\t\t\t\t\tvid, err := strconv.Atoi(vidStr)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"invalid vid: %s\", vidStr)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif vid < minVID2 || vid > maxVID2 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"vid %d is out of expected range [%d-%d]\", vid, minVID2, maxVID2)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxAvailableVLAN_multipleParallel tests that multiple available VLANs\n// can be allocated in parallel from the same VLAN group.\nfunc TestAccNetboxAvailableVLAN_multipleParallel(t *testing.T) {\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: `\nresource \"netbox_site\" \"test_site\" {\n  name = \"Parallel Test Site\"\n  slug = \"Parallel-test-site\"\n}\n\nresource \"netbox_vlan_group\" \"group2\" {\n  name        = \"Group Two\"\n  slug        = \"group-two\"\n  scope_id    = netbox_site.test_site.id\n  scope_type  = \"dcim.site\"\n  vid_ranges  = [[30, 32]]\n}\n\nresource \"netbox_available_vlan\" \"vlan1\" {\n  name     = \"vlan-1\"\n  status   = \"active\"\n  group_id = netbox_vlan_group.group2.id\n  site_id  = netbox_vlan_group.group2.scope_id\n}\n\nresource \"netbox_available_vlan\" \"vlan2\" {\n  name     = \"vlan-2\"\n  status   = \"active\"\n  group_id = netbox_vlan_group.group2.id\n  site_id  = netbox_vlan_group.group2.scope_id\n}\n`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan1\", \"vid\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan2\", \"vid\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxAvailableVLAN_vidExhaustion validates that the provider returns\n// an appropriate error when trying to allocate more VLANs than the defined\n// vid_ranges allow (i.e., resource exhaustion).\nfunc TestAccNetboxAvailableVLAN_vidExhaustion(t *testing.T) {\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: `\nresource \"netbox_vlan_group\" \"group\" {\n  name = \"Exhausted VLAN Group\"\n  slug = \"exhausted\"\n  vid_ranges = [[500, 500]]\n}\n\nresource \"netbox_available_vlan\" \"vlan1\" {\n  name     = \"exhausted-vlan-1\"\n  group_id = netbox_vlan_group.group.id\n  status   = \"active\"\n}\n\nresource \"netbox_available_vlan\" \"vlan2\" {\n  name     = \"exhausted-vlan-2\"\n  group_id = netbox_vlan_group.group.id\n  status   = \"active\"\n}\n`,\n\t\t\t\tExpectError: regexp.MustCompile(`(?i)(409|400|no available vlans|must be greater than or equal to)`),\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxAvailableVLAN_withTenant verifies that a VLAN can be created\n// with a specific tenant. It ensures the tenant_id is correctly\n// assigned and persisted by the provider.\n// NOTE: This test could also be run with tenant AND role but the vlan-role\n// is not yet implemented in the netbox API (as of 05.05.2025 at least)\nfunc TestAccNetboxAvailableVLAN_withTenant(t *testing.T) {\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: `\nresource \"netbox_tenant\" \"tenant\" {\n  name = \"TestTenant\"\n  slug = \"testtenant\"\n}\n\nresource \"netbox_vlan_group\" \"group\" {\n  name = \"VLAN Role Test\"\n  slug = \"vlan-role-test\"\n  vid_ranges = [[400, 405]]\n}\n\nresource \"netbox_available_vlan\" \"vlan\" {\n  name       = \"vlan-role-tenant\"\n  group_id   = netbox_vlan_group.group.id\n  tenant_id  = netbox_tenant.tenant.id\n  status     = \"active\"\n}\n`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_available_vlan.vlan\", \"tenant_id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_cable.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxCable() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxCableCreate,\n\t\tRead:   resourceNetboxCableRead,\n\t\tUpdate: resourceNetboxCableUpdate,\n\t\tDelete: resourceNetboxCableDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/cable/):\n\n> All connections between device components in NetBox are represented using cables. A cable represents a direct physical connection between two sets of endpoints (A and B), such as a console port and a patch panel port, or between two network interfaces.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"a_termination\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tRequired: true,\n\t\t\t\tElem:     genericObjectSchema,\n\t\t\t},\n\t\t\t\"b_termination\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tRequired: true,\n\t\t\t\tElem:     genericObjectSchema,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tDescription:  \"One of [connected, planned, decommissioning]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"connected\", \"planned\", \"decommissioning\"}, false),\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"One of [cat3, cat5, cat5e, cat6, cat6a, cat7, cat7a, cat8, dac-active, dac-passive, mrj21-trunk, coaxial, mmf, mmf-om1, mmf-om2, mmf-om3, mmf-om4, mmf-om5, smf, smf-os1, smf-os2, aoc, power, usb]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\n\t\t\t\t\t\"cat3\", \"cat5\", \"cat5e\", \"cat6\", \"cat6a\", \"cat7\", \"cat7a\", \"cat8\", \"dac-active\",\n\t\t\t\t\t\"dac-passive\", \"mrj21-trunk\", \"coaxial\", \"mmf\", \"mmf-om1\", \"mmf-om2\", \"mmf-om3\",\n\t\t\t\t\t\"mmf-om4\", \"mmf-om5\", \"smf\", \"smf-os1\", \"smf-os2\", \"aoc\", \"power\", \"usb\",\n\t\t\t\t}, false),\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"length\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"length_unit\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"length\"},\n\t\t\t\tDescription:  \"One of [km, m, cm, mi, ft, in]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"km\", \"m\", \"cm\", \"mi\", \"ft\", \"in\"}, false),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxCableCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableCable{\n\t\tStatus:      d.Get(\"status\").(string),\n\t\tType:        getOptionalStr(d, \"type\", false),\n\t\tTenant:      getOptionalInt(d, \"tenant_id\"),\n\t\tLabel:       getOptionalStr(d, \"label\", false),\n\t\tColor:       getOptionalStr(d, \"color_hex\", false),\n\t\tLength:      getOptionalFloat(d, \"length\"),\n\t\tLengthUnit:  getOptionalStr(d, \"length_unit\", false),\n\t\tDescription: getOptionalStr(d, \"description\", false),\n\t\tComments:    getOptionalStr(d, \"comments\", false),\n\t}\n\n\taTerminations := d.Get(\"a_termination\").(*schema.Set)\n\tdata.ATerminations = getGenericObjectsFromSchemaSet(aTerminations)\n\n\tbTerminations := d.Get(\"b_termination\").(*schema.Set)\n\tdata.BTerminations = getGenericObjectsFromSchemaSet(bTerminations)\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimCablesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimCablesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxCableRead(d, m)\n}\n\nfunc resourceNetboxCableRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimCablesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimCablesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimCablesReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tcable := res.GetPayload()\n\n\td.Set(\"a_termination\", getSchemaSetFromGenericObjects(cable.ATerminations))\n\td.Set(\"b_termination\", getSchemaSetFromGenericObjects(cable.BTerminations))\n\n\tif cable.Status != nil {\n\t\td.Set(\"status\", cable.Status.Value)\n\t} else {\n\t\td.Set(\"status\", nil)\n\t}\n\n\td.Set(\"type\", cable.Type)\n\n\tif cable.Tenant != nil {\n\t\td.Set(\"tenant_id\", cable.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\td.Set(\"label\", cable.Label)\n\td.Set(\"color_hex\", cable.Color)\n\td.Set(\"length\", cable.Length)\n\n\tif cable.LengthUnit != nil {\n\t\td.Set(\"length_unit\", cable.LengthUnit.Value)\n\t} else {\n\t\td.Set(\"length_unit\", nil)\n\t}\n\n\td.Set(\"description\", cable.Description)\n\td.Set(\"comments\", cable.Comments)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxCableUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableCable{\n\t\tStatus:      d.Get(\"status\").(string),\n\t\tType:        getOptionalStr(d, \"type\", false),\n\t\tTenant:      getOptionalInt(d, \"tenant_id\"),\n\t\tLabel:       getOptionalStr(d, \"label\", true),\n\t\tColor:       getOptionalStr(d, \"color_hex\", false),\n\t\tLength:      getOptionalFloat(d, \"length\"),\n\t\tLengthUnit:  getOptionalStr(d, \"length_unit\", false),\n\t\tDescription: getOptionalStr(d, \"description\", true),\n\t\tComments:    getOptionalStr(d, \"comments\", true),\n\t}\n\n\taTerminations := d.Get(\"a_termination\").(*schema.Set)\n\tdata.ATerminations = getGenericObjectsFromSchemaSet(aTerminations)\n\n\tbTerminations := d.Get(\"b_termination\").(*schema.Set)\n\tdata.BTerminations = getGenericObjectsFromSchemaSet(bTerminations)\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimCablesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimCablesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxCableRead(d, m)\n}\n\nfunc resourceNetboxCableDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimCablesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimCablesDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_cable_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxCableFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id = netbox_device.test.id\n  module_bay_id = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status = \"active\"\n}\n\nresource \"netbox_device_console_port\" \"test1\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s1\"\n}\n\nresource \"netbox_device_console_port\" \"test2\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s2\"\n}\n\nresource \"netbox_device_console_server_port\" \"test1\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s1\"\n}\n\nresource \"netbox_device_console_server_port\" \"test2\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s2\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxCable_basic(t *testing.T) {\n\ttestSlug := \"cable_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckCableDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxCableFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_cable\" \"test\" {\n  a_termination {\n\t\tobject_type = \"dcim.consoleserverport\"\n\t\tobject_id = netbox_device_console_server_port.test1.id\n\t}\n\ta_termination {\n\t\tobject_type = \"dcim.consoleserverport\"\n\t\tobject_id = netbox_device_console_server_port.test2.id\n\t}\n\n\tb_termination {\n\t\tobject_type = \"dcim.consoleport\"\n\t\tobject_id = netbox_device_console_port.test1.id\n\t}\n\tb_termination {\n\t\tobject_type = \"dcim.consoleport\"\n\t\tobject_id = netbox_device_console_port.test2.id\n\t}\n\n\tstatus = \"connected\"\n\tlabel = \"%[1]s_label\"\n\ttype = \"cat8\"\n\ttenant_id = netbox_tenant.test.id\n\tcolor_hex = \"123456\"\n\tlength = 10\n\tlength_unit = \"m\"\n\tdescription = \"%[1]s_description\"\n\tcomments = \"%[1]s_comments\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"status\", \"connected\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"type\", \"cat8\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"color_hex\", \"123456\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"length\", \"10\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"length_unit\", \"m\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"comments\", testName+\"_comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"a_termination.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"a_termination.0.object_type\", \"dcim.consoleserverport\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"a_termination.1.object_type\", \"dcim.consoleserverport\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttrPair(\"netbox_cable.test\", \"a_termination.*.object_id\", \"netbox_device_console_server_port.test1\", \"id\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttrPair(\"netbox_cable.test\", \"a_termination.*.object_id\", \"netbox_device_console_server_port.test2\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"b_termination.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"b_termination.0.object_type\", \"dcim.consoleport\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"b_termination.1.object_type\", \"dcim.consoleport\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttrPair(\"netbox_cable.test\", \"b_termination.*.object_id\", \"netbox_device_console_port.test1\", \"id\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttrPair(\"netbox_cable.test\", \"b_termination.*.object_id\", \"netbox_device_console_port.test2\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cable.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxCableFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_cable\" \"test\" {\n  a_termination {\n\t\tobject_type = \"dcim.consoleserverport\"\n\t\tobject_id = netbox_device_console_server_port.test1.id\n\t}\n\n\tb_termination {\n\t\tobject_type = \"dcim.consoleport\"\n\t\tobject_id = netbox_device_console_port.test1.id\n\t}\n\n\tstatus = \"connected\"\n\tlabel = \"%[1]s_label\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"status\", \"connected\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"type\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"color_hex\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"length\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"length_unit\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"tenant_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"a_termination.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"a_termination.0.object_type\", \"dcim.consoleserverport\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cable.test\", \"a_termination.0.object_id\", \"netbox_device_console_server_port.test1\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"b_termination.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cable.test\", \"b_termination.0.object_type\", \"dcim.consoleport\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cable.test\", \"b_termination.0.object_id\", \"netbox_device_console_port.test1\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_cable.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckCableDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each cable\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_cable\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimCablesReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimCablesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"cable (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimCablesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_cable\", &resource.Sweeper{\n\t\tName:         \"netbox_cable\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimCablesListParams()\n\t\t\tres, err := api.Dcim.DcimCablesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, cable := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(cable.Label, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimCablesDeleteParams().WithID(cable.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimCablesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a cable\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_circuit.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/circuits\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxCircuitStatusOptions = []string{\"planned\", \"provisioning\", \"active\", \"offline\", \"deprovisioning\", \"decommissioning\"}\n\nfunc resourceNetboxCircuit() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxCircuitCreate,\n\t\tRead:   resourceNetboxCircuitRead,\n\t\tUpdate: resourceNetboxCircuitUpdate,\n\t\tDelete: resourceNetboxCircuitDelete,\n\n\t\tDescription: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuits_1):\n\n> A communications circuit represents a single physical link connecting exactly two endpoints, commonly referred to as its A and Z terminations. A circuit in NetBox may have zero, one, or two terminations defined. It is common to have only one termination defined when you don't necessarily care about the details of the provider side of the circuit, e.g. for Internet access circuits. Both terminations would likely be modeled for circuits which connect one customer site to another.\n>\n> Each circuit is associated with a provider and a user-defined type. For example, you might have Internet access circuits delivered to each site by one provider, and private MPLS circuits delivered by another. Each circuit must be assigned a circuit ID, each of which must be unique per provider.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"provider_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"cid\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"type_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxCircuitStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxCircuitStatusOptions),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxCircuitCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableCircuit{}\n\n\tcid := d.Get(\"cid\").(string)\n\tdata.Cid = &cid\n\n\tdata.Status = d.Get(\"status\").(string)\n\tdata.Description = d.Get(\"description\").(string)\n\n\tproviderIDValue, ok := d.GetOk(\"provider_id\")\n\tif ok {\n\t\tdata.Provider = int64ToPtr(int64(providerIDValue.(int)))\n\t}\n\n\ttypeIDValue, ok := d.GetOk(\"type_id\")\n\tif ok {\n\t\tdata.Type = int64ToPtr(int64(typeIDValue.(int)))\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantIDValue.(int)))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := circuits.NewCircuitsCircuitsCreateParams().WithData(&data)\n\n\tres, err := api.Circuits.CircuitsCircuitsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxCircuitRead(d, m)\n}\n\nfunc resourceNetboxCircuitRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := circuits.NewCircuitsCircuitsReadParams().WithID(id)\n\n\tres, err := api.Circuits.CircuitsCircuitsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*circuits.CircuitsCircuitsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"cid\", res.GetPayload().Cid)\n\td.Set(\"status\", res.GetPayload().Status.Value)\n\td.Set(\"description\", res.GetPayload().Description)\n\n\tif res.GetPayload().Provider != nil {\n\t\td.Set(\"provider_id\", res.GetPayload().Provider.ID)\n\t} else {\n\t\td.Set(\"provider_id\", nil)\n\t}\n\n\tif res.GetPayload().Type != nil {\n\t\td.Set(\"type_id\", res.GetPayload().Type.ID)\n\t} else {\n\t\td.Set(\"type_id\", nil)\n\t}\n\n\tif res.GetPayload().Tenant != nil {\n\t\td.Set(\"tenant_id\", res.GetPayload().Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxCircuitUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableCircuit{}\n\n\tcid := d.Get(\"cid\").(string)\n\tdata.Cid = &cid\n\n\tdata.Status = d.Get(\"status\").(string)\n\tdata.Description = d.Get(\"description\").(string)\n\n\tproviderIDValue, ok := d.GetOk(\"provider_id\")\n\tif ok {\n\t\tdata.Provider = int64ToPtr(int64(providerIDValue.(int)))\n\t}\n\n\ttypeIDValue, ok := d.GetOk(\"type_id\")\n\tif ok {\n\t\tdata.Type = int64ToPtr(int64(typeIDValue.(int)))\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantIDValue.(int)))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := circuits.NewCircuitsCircuitsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Circuits.CircuitsCircuitsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxCircuitRead(d, m)\n}\n\nfunc resourceNetboxCircuitDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := circuits.NewCircuitsCircuitsDeleteParams().WithID(id)\n\n\t_, err := api.Circuits.CircuitsCircuitsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*circuits.CircuitsCircuitsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_circuit_provider.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/circuits\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxCircuitProvider() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxCircuitProviderCreate,\n\t\tRead:   resourceNetboxCircuitProviderRead,\n\t\tUpdate: resourceNetboxCircuitProviderUpdate,\n\t\tDelete: resourceNetboxCircuitProviderDelete,\n\n\t\tDescription: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#providers):\n\n> A circuit provider is any entity which provides some form of connectivity of among sites or organizations within a site. While this obviously includes carriers which offer Internet and private transit service, it might also include Internet exchange (IX) points and even organizations with whom you peer directly. Each circuit within NetBox must be assigned a provider and a circuit ID which is unique to that provider.\n>\n> Each provider may be assigned an autonomous system number (ASN), an account number, and contact information.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxCircuitProviderCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableProvider{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tdata.Description = d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\tdata.Asns = []int64{}\n\n\tparams := circuits.NewCircuitsProvidersCreateParams().WithData(&data)\n\n\tres, err := api.Circuits.CircuitsProvidersCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxCircuitProviderRead(d, m)\n}\n\nfunc resourceNetboxCircuitProviderRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := circuits.NewCircuitsProvidersReadParams().WithID(id)\n\n\tres, err := api.Circuits.CircuitsProvidersRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*circuits.CircuitsProvidersReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"description\", res.GetPayload().Description)\n\n\treturn nil\n}\n\nfunc resourceNetboxCircuitProviderUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableProvider{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tdata.Description = d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\tdata.Asns = []int64{}\n\n\tparams := circuits.NewCircuitsProvidersPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Circuits.CircuitsProvidersPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxCircuitProviderRead(d, m)\n}\n\nfunc resourceNetboxCircuitProviderDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := circuits.NewCircuitsProvidersDeleteParams().WithID(id)\n\n\t_, err := api.Circuits.CircuitsProvidersDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_circuit_provider_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/circuits\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxCircuitProvider_basic(t *testing.T) {\n\ttestSlug := \"circuit_prov\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_circuit_provider\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  description = \"This is my circuit provider!\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_provider.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_provider.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_provider.test\", \"description\", \"This is my circuit provider!\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_circuit_provider\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  description = \"This is my circuit provider!\"\n}`, testName+\"2\", randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_provider.test\", \"name\", testName+\"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_provider.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_provider.test\", \"description\", \"This is my circuit provider!\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_circuit_provider.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_circuit_provider\", &resource.Sweeper{\n\t\tName:         \"netbox_circuit_provider\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := circuits.NewCircuitsProvidersListParams()\n\t\t\tres, err := api.Circuits.CircuitsProvidersList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, CircuitProvider := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*CircuitProvider.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := circuits.NewCircuitsProvidersDeleteParams().WithID(CircuitProvider.ID)\n\t\t\t\t\t_, err := api.Circuits.CircuitsProvidersDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a circuit provider\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_circuit_termination.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/circuits\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxCircuitTerminationTermSideOptions = []string{\"A\", \"Z\"}\n\nfunc resourceNetboxCircuitTermination() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxCircuitTerminationCreate,\n\t\tRead:   resourceNetboxCircuitTerminationRead,\n\t\tUpdate: resourceNetboxCircuitTerminationUpdate,\n\t\tDelete: resourceNetboxCircuitTerminationDelete,\n\n\t\tDescription: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuit-terminations):\n\n> The association of a circuit with a particular site and/or device is modeled separately as a circuit termination. A circuit may have up to two terminations, labeled A and Z. A single-termination circuit can be used when you don't know (or care) about the far end of a circuit (for example, an Internet access circuit which connects to a transit provider). A dual-termination circuit is useful for tracking circuits which connect two sites.\n>\n> Each circuit termination is attached to either a site or to a provider network. Site terminations may optionally be connected via a cable to a specific device interface or port within that site. Each termination must be assigned a port speed, and can optionally be assigned an upstream speed if it differs from the downstream speed (a common scenario with e.g. DOCSIS cable modems). Fields are also available to track cross-connect and patch panel details.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"circuit_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"site_id\", \"site_group_id\", \"region_id\", \"provider_network_id\"},\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"location_id\", \"site_group_id\", \"region_id\", \"provider_network_id\"},\n\t\t\t},\n\t\t\t\"site_group_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"location_id\", \"site_id\", \"region_id\", \"provider_network_id\"},\n\t\t\t},\n\t\t\t\"region_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"location_id\", \"site_id\", \"site_group_id\", \"provider_network_id\"},\n\t\t\t},\n\t\t\t\"provider_network_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"location_id\", \"site_id\", \"site_group_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"port_speed\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"upstream_speed\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"term_side\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxCircuitTerminationTermSideOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxCircuitTerminationTermSideOptions),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxCircuitTerminationCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableCircuitTermination{}\n\n\ttermside := d.Get(\"term_side\").(string)\n\tdata.TermSide = &termside\n\tdata.Description = d.Get(\"description\").(string)\n\n\tcircuitIDValue, ok := d.GetOk(\"circuit_id\")\n\tif ok {\n\t\tdata.Circuit = int64ToPtr(int64(circuitIDValue.(int)))\n\t}\n\n\tsiteID := getOptionalInt(d, \"site_id\")\n\tsiteGroupID := getOptionalInt(d, \"site_group_id\")\n\tlocationID := getOptionalInt(d, \"location_id\")\n\tregionID := getOptionalInt(d, \"region_id\")\n\tproviderNetworkID := getOptionalInt(d, \"provider_network_id\")\n\n\tswitch {\n\tcase siteID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.site\")\n\t\tdata.TerminationID = siteID\n\tcase siteGroupID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.sitegroup\")\n\t\tdata.TerminationID = siteGroupID\n\tcase locationID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.location\")\n\t\tdata.TerminationID = locationID\n\tcase regionID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.region\")\n\t\tdata.TerminationID = regionID\n\tcase providerNetworkID != nil:\n\t\tdata.TerminationType = strToPtr(\"circuits.providernetwork\")\n\t\tdata.TerminationID = providerNetworkID\n\tdefault:\n\t\tdata.TerminationType = nil\n\t\tdata.TerminationID = nil\n\t}\n\n\tportspeedValue, ok := d.GetOk(\"port_speed\")\n\tif ok {\n\t\tdata.PortSpeed = int64ToPtr(int64(portspeedValue.(int)))\n\t}\n\n\tupstreamspeedValue, ok := d.GetOk(\"upstream_speed\")\n\tif ok {\n\t\tdata.UpstreamSpeed = int64ToPtr(int64(upstreamspeedValue.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := circuits.NewCircuitsCircuitTerminationsCreateParams().WithData(&data)\n\n\tres, err := api.Circuits.CircuitsCircuitTerminationsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxCircuitTerminationRead(d, m)\n}\n\nfunc resourceNetboxCircuitTerminationRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := circuits.NewCircuitsCircuitTerminationsReadParams().WithID(id)\n\n\tres, err := api.Circuits.CircuitsCircuitTerminationsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*circuits.CircuitsCircuitTerminationsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tterm := res.GetPayload()\n\n\td.Set(\"term_side\", term.TermSide)\n\n\tif term.Circuit != nil {\n\t\td.Set(\"circuit_id\", term.Circuit.ID)\n\t} else {\n\t\td.Set(\"circuit_id\", nil)\n\t}\n\n\td.Set(\"site_id\", nil)\n\td.Set(\"site_group_id\", nil)\n\td.Set(\"location_id\", nil)\n\td.Set(\"region_id\", nil)\n\td.Set(\"provider_network_id\", nil)\n\td.Set(\"description\", res.GetPayload().Description)\n\n\tif term.TerminationType != nil && term.TerminationID != nil {\n\t\tscopeID := term.TerminationID\n\t\tswitch scopeType := term.TerminationType; *scopeType {\n\t\tcase \"dcim.site\":\n\t\t\td.Set(\"site_id\", scopeID)\n\t\tcase \"dcim.sitegroup\":\n\t\t\td.Set(\"site_group_id\", scopeID)\n\t\tcase \"dcim.location\":\n\t\t\td.Set(\"location_id\", scopeID)\n\t\tcase \"dcim.region\":\n\t\t\td.Set(\"region_id\", scopeID)\n\t\tcase \"circuits.providernetwork\":\n\t\t\td.Set(\"provider_network_id\", scopeID)\n\t\t}\n\t}\n\n\tif term.PortSpeed != nil {\n\t\td.Set(\"port_speed\", term.PortSpeed)\n\t} else {\n\t\td.Set(\"port_speed\", nil)\n\t}\n\n\tif term.UpstreamSpeed != nil {\n\t\td.Set(\"upstream_speed\", term.UpstreamSpeed)\n\t} else {\n\t\td.Set(\"upstream_speed\", nil)\n\t}\n\n\tapi.readTags(d, term.Tags)\n\n\tcf := getCustomFields(term.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxCircuitTerminationUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableCircuitTermination{}\n\n\ttermside := d.Get(\"term_side\").(string)\n\tdata.TermSide = &termside\n\tdata.Description = d.Get(\"description\").(string)\n\n\tcircuitIDValue, ok := d.GetOk(\"circuit_id\")\n\tif ok {\n\t\tdata.Circuit = int64ToPtr(int64(circuitIDValue.(int)))\n\t}\n\n\tsiteID := getOptionalInt(d, \"site_id\")\n\tsiteGroupID := getOptionalInt(d, \"site_group_id\")\n\tlocationID := getOptionalInt(d, \"location_id\")\n\tregionID := getOptionalInt(d, \"region_id\")\n\tproviderNetworkID := getOptionalInt(d, \"provider_network_id\")\n\n\tswitch {\n\tcase siteID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.site\")\n\t\tdata.TerminationID = siteID\n\tcase siteGroupID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.sitegroup\")\n\t\tdata.TerminationID = siteGroupID\n\tcase locationID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.location\")\n\t\tdata.TerminationID = locationID\n\tcase regionID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.region\")\n\t\tdata.TerminationID = regionID\n\tcase providerNetworkID != nil:\n\t\tdata.TerminationType = strToPtr(\"circuits.providernetwork\")\n\t\tdata.TerminationID = providerNetworkID\n\tdefault:\n\t\tdata.TerminationType = nil\n\t\tdata.TerminationID = nil\n\t}\n\n\tportspeedValue, ok := d.GetOk(\"port_speed\")\n\tif ok {\n\t\tdata.PortSpeed = int64ToPtr(int64(portspeedValue.(int)))\n\t}\n\n\tupstreamspeedValue, ok := d.GetOk(\"upstream_speed\")\n\tif ok {\n\t\tdata.UpstreamSpeed = int64ToPtr(int64(upstreamspeedValue.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := circuits.NewCircuitsCircuitTerminationsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Circuits.CircuitsCircuitTerminationsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxCircuitTerminationRead(d, m)\n}\n\nfunc resourceNetboxCircuitTerminationDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := circuits.NewCircuitsCircuitTerminationsDeleteParams().WithID(id)\n\n\t_, err := api.Circuits.CircuitsCircuitTerminationsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*circuits.CircuitsCircuitTerminationsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_circuit_termination_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/circuits\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxCircuitTermination_basic(t *testing.T) {\n\ttestSlug := \"circuit_term\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  status = \"active\"\n}\nresource \"netbox_circuit_provider\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n}\nresource \"netbox_circuit_type\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n}\nresource \"netbox_circuit\" \"test\" {\n  cid = \"%[1]s\"\n  status = \"active\"\n  provider_id = netbox_circuit_provider.test.id\n  type_id = netbox_circuit_type.test.id\n}\nresource \"netbox_circuit_termination\" \"test\" {\n  circuit_id = netbox_circuit.test.id\n  term_side = \"A\"\n  site_id = netbox_site.test.id\n  port_speed = 100000\n  upstream_speed = 50000\n  description = \"This is my circuit termination!\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_circuit_termination.test\", \"circuit_id\", \"netbox_circuit.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_circuit_termination.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_termination.test\", \"port_speed\", \"100000\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_termination.test\", \"upstream_speed\", \"50000\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_termination.test\", \"description\", \"This is my circuit termination!\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_circuit_termination.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_circuit_termination\", &resource.Sweeper{\n\t\tName:         \"netbox_circuit_termination\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := circuits.NewCircuitsCircuitsListParams()\n\t\t\tres, err := api.Circuits.CircuitsCircuitsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, Circuit := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*Circuit.Cid, testPrefix) {\n\t\t\t\t\tdeleteParams := circuits.NewCircuitsCircuitsDeleteParams().WithID(Circuit.ID)\n\t\t\t\t\t_, err := api.Circuits.CircuitsCircuitsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a circuit termination\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_circuit_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/circuits\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxCircuitDependencies(testName string, testSlug string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n\tname = \"%[1]s\"\n\tslug = \"%[2]s\"\n}\nresource \"netbox_circuit_provider\" \"test\" {\n\tname = \"%[1]s\"\n\tslug = \"%[2]s\"\n}\nresource \"netbox_circuit_type\" \"test\" {\n\tname = \"%[1]s\"\n\tslug = \"%[2]s\"\n}\n`, testName, testSlug)\n}\nfunc TestAccNetboxCircuit_basic(t *testing.T) {\n\ttestSlug := \"circuit_prov\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxCircuitDependencies(testName, randomSlug) + fmt.Sprintf(`\nresource \"netbox_circuit\" \"test\" {\n  cid = \"%[1]s\"\n  status = \"active\"\n  description = \"This is my circuit!\"\n  provider_id = netbox_circuit_provider.test.id\n  type_id = netbox_circuit_type.test.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit.test\", \"cid\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_circuit.test\", \"provider_id\", \"netbox_circuit_provider.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_circuit.test\", \"type_id\", \"netbox_circuit_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit.test\", \"description\", \"This is my circuit!\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxCircuitDependencies(testName, randomSlug) + fmt.Sprintf(`\nresource \"netbox_circuit\" \"test\" {\n  cid = \"%[1]s\"\n  status = \"active\"\n  description = \"This is my circuit!\"\n  provider_id = netbox_circuit_provider.test.id\n  type_id = netbox_circuit_type.test.id\n  tenant_id = netbox_tenant.test.id\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit.test\", \"cid\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_circuit.test\", \"provider_id\", \"netbox_circuit_provider.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_circuit.test\", \"type_id\", \"netbox_circuit_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_circuit.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit.test\", \"description\", \"This is my circuit!\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_circuit.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_circuit\", &resource.Sweeper{\n\t\tName:         \"netbox_circuit\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := circuits.NewCircuitsCircuitsListParams()\n\t\t\tres, err := api.Circuits.CircuitsCircuitsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, Circuit := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*Circuit.Cid, testPrefix) {\n\t\t\t\t\tdeleteParams := circuits.NewCircuitsCircuitsDeleteParams().WithID(Circuit.ID)\n\t\t\t\t\t_, err := api.Circuits.CircuitsCircuitsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a circuit\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_circuit_type.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/circuits\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxCircuitType() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxCircuitTypeCreate,\n\t\tRead:   resourceNetboxCircuitTypeRead,\n\t\tUpdate: resourceNetboxCircuitTypeUpdate,\n\t\tDelete: resourceNetboxCircuitTypeDelete,\n\n\t\tDescription: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuit-types):\n\n> Circuits are classified by functional type. These types are completely customizable, and are typically used to convey the type of service being delivered over a circuit.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxCircuitTypeCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.CircuitType{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tdata.Description = d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := circuits.NewCircuitsCircuitTypesCreateParams().WithData(&data)\n\n\tres, err := api.Circuits.CircuitsCircuitTypesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxCircuitTypeRead(d, m)\n}\n\nfunc resourceNetboxCircuitTypeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := circuits.NewCircuitsCircuitTypesReadParams().WithID(id)\n\n\tres, err := api.Circuits.CircuitsCircuitTypesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*circuits.CircuitsCircuitTypesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"description\", res.GetPayload().Description)\n\n\treturn nil\n}\n\nfunc resourceNetboxCircuitTypeUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.CircuitType{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tdata.Description = d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := circuits.NewCircuitsCircuitTypesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Circuits.CircuitsCircuitTypesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxCircuitTypeRead(d, m)\n}\n\nfunc resourceNetboxCircuitTypeDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := circuits.NewCircuitsCircuitTypesDeleteParams().WithID(id)\n\n\t_, err := api.Circuits.CircuitsCircuitTypesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*circuits.CircuitsCircuitTypesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_circuit_type_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/circuits\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxCircuitType_basic(t *testing.T) {\n\ttestSlug := \"circuit_type\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_circuit_type\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  description = \"This is my circuit type!\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_type.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_type.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_circuit_type.test\", \"description\", \"This is my circuit type!\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_circuit_type.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_circuit_type\", &resource.Sweeper{\n\t\tName:         \"netbox_circuit_type\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := circuits.NewCircuitsCircuitTypesListParams()\n\t\t\tres, err := api.Circuits.CircuitsCircuitTypesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, CircuitType := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*CircuitType.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := circuits.NewCircuitsCircuitTypesDeleteParams().WithID(CircuitType.ID)\n\t\t\t\t\t_, err := api.Circuits.CircuitsCircuitTypesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a circuit type\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_cluster.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxCluster() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxClusterCreate,\n\t\tRead:   resourceNetboxClusterRead,\n\t\tUpdate: resourceNetboxClusterUpdate,\n\t\tDelete: resourceNetboxClusterDelete,\n\n\t\tDescription: `:meta:subcategory:Virtualization:From the [official documentation](https://netboxlabs.com/docs/netbox/models/virtualization/cluster/):\n> A cluster is a logical grouping of physical resources within which virtual machines run. Physical devices may be associated with clusters as hosts. This allows users to track on which host(s) a particular virtual machine may reside.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"cluster_type_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"cluster_group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"site_id\", \"site_group_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_group_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"site_group_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"region_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_id\", \"site_group_id\"},\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxClusterCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableCluster{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tclusterTypeID := int64(d.Get(\"cluster_type_id\").(int))\n\tdata.Type = &clusterTypeID\n\n\tsiteID := getOptionalInt(d, \"site_id\")\n\tsiteGroupID := getOptionalInt(d, \"site_group_id\")\n\tlocationID := getOptionalInt(d, \"location_id\")\n\tregionID := getOptionalInt(d, \"region_id\")\n\n\tswitch {\n\tcase siteID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.site\")\n\t\tdata.ScopeID = siteID\n\tcase siteGroupID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.sitegroup\")\n\t\tdata.ScopeID = siteGroupID\n\tcase locationID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.location\")\n\t\tdata.ScopeID = locationID\n\tcase regionID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.region\")\n\t\tdata.ScopeID = regionID\n\tdefault:\n\t\tdata.ScopeType = nil\n\t\tdata.ScopeID = nil\n\t}\n\n\tif clusterGroupIDValue, ok := d.GetOk(\"cluster_group_id\"); ok {\n\t\tclusterGroupID := int64(clusterGroupIDValue.(int))\n\t\tdata.Group = &clusterGroupID\n\t}\n\n\tdata.Comments = getOptionalStr(d, \"comments\", false)\n\tdata.Description = getOptionalStr(d, \"description\", false)\n\n\tif tenantIDValue, ok := d.GetOk(\"tenant_id\"); ok {\n\t\ttenantID := int64(tenantIDValue.(int))\n\t\tdata.Tenant = &tenantID\n\t}\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tparams := virtualization.NewVirtualizationClustersCreateParams().WithData(&data)\n\n\tres, err := api.Virtualization.VirtualizationClustersCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxClusterRead(d, m)\n}\n\nfunc resourceNetboxClusterRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationClustersReadParams().WithID(id)\n\n\tres, err := api.Virtualization.VirtualizationClustersRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationClustersReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tcluster := res.GetPayload()\n\n\td.Set(\"name\", cluster.Name)\n\td.Set(\"cluster_type_id\", cluster.Type.ID)\n\n\tif cluster.Group != nil {\n\t\td.Set(\"cluster_group_id\", cluster.Group.ID)\n\t} else {\n\t\td.Set(\"cluster_group_id\", nil)\n\t}\n\n\td.Set(\"comments\", cluster.Comments)\n\td.Set(\"description\", cluster.Description)\n\n\tif cluster.Tenant != nil {\n\t\td.Set(\"tenant_id\", cluster.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\td.Set(\"site_id\", nil)\n\td.Set(\"site_group_id\", nil)\n\td.Set(\"location_id\", nil)\n\td.Set(\"region_id\", nil)\n\n\tif cluster.ScopeType != nil && cluster.ScopeID != nil {\n\t\tscopeID := cluster.ScopeID\n\t\tswitch scopeType := cluster.ScopeType; *scopeType {\n\t\tcase \"dcim.site\":\n\t\t\td.Set(\"site_id\", scopeID)\n\t\tcase \"dcim.sitegroup\":\n\t\t\td.Set(\"site_group_id\", scopeID)\n\t\tcase \"dcim.location\":\n\t\t\td.Set(\"location_id\", scopeID)\n\t\tcase \"dcim.region\":\n\t\t\td.Set(\"region_id\", scopeID)\n\t\t}\n\t}\n\n\tapi.readTags(d, res.GetPayload().Tags)\n\treturn nil\n}\n\nfunc resourceNetboxClusterUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableCluster{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tclusterTypeID := int64(d.Get(\"cluster_type_id\").(int))\n\tdata.Type = &clusterTypeID\n\n\tif clusterGroupIDValue, ok := d.GetOk(\"cluster_group_id\"); ok {\n\t\tclusterGroupID := int64(clusterGroupIDValue.(int))\n\t\tdata.Group = &clusterGroupID\n\t}\n\n\tdata.Comments = getOptionalStr(d, \"comments\", true)\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\n\tif tenantIDValue, ok := d.GetOk(\"tenant_id\"); ok {\n\t\ttenantID := int64(tenantIDValue.(int))\n\t\tdata.Tenant = &tenantID\n\t}\n\n\tsiteID := getOptionalInt(d, \"site_id\")\n\tsiteGroupID := getOptionalInt(d, \"site_group_id\")\n\tlocationID := getOptionalInt(d, \"location_id\")\n\tregionID := getOptionalInt(d, \"region_id\")\n\n\tswitch {\n\tcase siteID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.site\")\n\t\tdata.ScopeID = siteID\n\tcase siteGroupID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.sitegroup\")\n\t\tdata.ScopeID = siteGroupID\n\tcase locationID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.location\")\n\t\tdata.ScopeID = locationID\n\tcase regionID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.region\")\n\t\tdata.ScopeID = regionID\n\tdefault:\n\t\tdata.ScopeType = nil\n\t\tdata.ScopeID = nil\n\t}\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tparams := virtualization.NewVirtualizationClustersPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Virtualization.VirtualizationClustersPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxClusterRead(d, m)\n}\n\nfunc resourceNetboxClusterDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationClustersDeleteParams().WithID(id)\n\n\t_, err := api.Virtualization.VirtualizationClustersDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationClustersDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_cluster_group.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxClusterGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxClusterGroupCreate,\n\t\tRead:   resourceNetboxClusterGroupRead,\n\t\tUpdate: resourceNetboxClusterGroupUpdate,\n\t\tDelete: resourceNetboxClusterGroupDelete,\n\n\t\tDescription: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#cluster-groups):\n\n> Cluster groups may be created for the purpose of organizing clusters. The arrangement of clusters into groups is optional.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxClusterGroupCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.ClusterGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\tdata.Slug = &slug\n\n\tif description, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = description.(string)\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := virtualization.NewVirtualizationClusterGroupsCreateParams().WithData(&data)\n\n\tres, err := api.Virtualization.VirtualizationClusterGroupsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxClusterGroupRead(d, m)\n}\n\nfunc resourceNetboxClusterGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationClusterGroupsReadParams().WithID(id)\n\n\tres, err := api.Virtualization.VirtualizationClusterGroupsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationClusterGroupsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"description\", res.GetPayload().Description)\n\treturn nil\n}\n\nfunc resourceNetboxClusterGroupUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.ClusterGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\tdata.Slug = &slug\n\n\tif d.HasChange(\"description\") {\n\t\t// description omits empty values so set to ' '\n\t\tif description := d.Get(\"description\"); description.(string) == \"\" {\n\t\t\tdata.Description = \" \"\n\t\t} else {\n\t\t\tdata.Description = description.(string)\n\t\t}\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := virtualization.NewVirtualizationClusterGroupsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Virtualization.VirtualizationClusterGroupsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxClusterGroupRead(d, m)\n}\n\nfunc resourceNetboxClusterGroupDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationClusterGroupsDeleteParams().WithID(id)\n\n\t_, err := api.Virtualization.VirtualizationClusterGroupsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationClusterGroupsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_cluster_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxClusterGroup_basic(t *testing.T) {\n\ttestSlug := \"clstrgrp_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_cluster_group\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[1]s\"\n  description = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_group.test\", \"slug\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_group.test\", \"description\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_cluster_group.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxClusterGroup_defaultSlug(t *testing.T) {\n\ttestSlug := \"clstrgrp_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_cluster_group\" \"test\" {\n  name = \"%[1]s\"\n  description = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_group.test\", \"slug\", getSlug(testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_group.test\", \"description\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_cluster_group\", &resource.Sweeper{\n\t\tName:         \"netbox_cluster_group\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := virtualization.NewVirtualizationClusterGroupsListParams()\n\t\t\tres, err := api.Virtualization.VirtualizationClusterGroupsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, clusterGroup := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*clusterGroup.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := virtualization.NewVirtualizationClusterGroupsDeleteParams().WithID(clusterGroup.ID)\n\t\t\t\t\t_, err := api.Virtualization.VirtualizationClusterGroupsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a cluster_group\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_cluster_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxCluster_basic(t *testing.T) {\n\ttestSlug := \"clstr_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  cluster_group_id = netbox_cluster_group.test.id\n  comments = \"%[1]scomments\"\n  description = \"%[1]sdescription\"\n  site_id = netbox_site.test.id\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cluster.test\", \"cluster_type_id\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cluster.test\", \"cluster_group_id\", \"netbox_cluster_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"comments\", testName+\"comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"description\", testName+\"description\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cluster.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"test_updatetag\" {\n  name = \"%[1]s-a\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name   = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  cluster_group_id = netbox_cluster_group.test.id\n  tenant_id = netbox_tenant.test.id\n  tags = [netbox_tag.test.name, netbox_tag.test_updatetag.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cluster.test\", \"cluster_type_id\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cluster.test\", \"cluster_group_id\", \"netbox_cluster_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_cluster.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"tags.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster.test\", \"tags.1\", fmt.Sprintf(\"%[1]s-a\", testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_cluster.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_cluster\", &resource.Sweeper{\n\t\tName:         \"netbox_cluster\",\n\t\tDependencies: []string{\"netbox_virtual_machine\", \"netbox_site\"},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := virtualization.NewVirtualizationClustersListParams()\n\t\t\tres, err := api.Virtualization.VirtualizationClustersList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, cluster := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*cluster.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := virtualization.NewVirtualizationClustersDeleteParams().WithID(cluster.ID)\n\t\t\t\t\t_, err := api.Virtualization.VirtualizationClustersDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a cluster\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_cluster_type.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxClusterType() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxClusterTypeCreate,\n\t\tRead:   resourceNetboxClusterTypeRead,\n\t\tUpdate: resourceNetboxClusterTypeUpdate,\n\t\tDelete: resourceNetboxClusterTypeDelete,\n\n\t\tDescription: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#cluster-types):\n\n> A cluster type represents a technology or mechanism by which a cluster is formed. For example, you might create a cluster type named \"VMware vSphere\" for a locally hosted cluster or \"DigitalOcean NYC3\" for one hosted by a cloud provider.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxClusterTypeCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tparams := virtualization.NewVirtualizationClusterTypesCreateParams().WithData(\n\t\t&models.ClusterType{\n\t\t\tName: &name,\n\t\t\tSlug: &slug,\n\t\t\tTags: []*models.NestedTag{},\n\t\t},\n\t)\n\n\tres, err := api.Virtualization.VirtualizationClusterTypesCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxClusterTypeRead(d, m)\n}\n\nfunc resourceNetboxClusterTypeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationClusterTypesReadParams().WithID(id)\n\n\tres, err := api.Virtualization.VirtualizationClusterTypesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationClusterTypesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\treturn nil\n}\n\nfunc resourceNetboxClusterTypeUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.ClusterType{}\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := virtualization.NewVirtualizationClusterTypesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Virtualization.VirtualizationClusterTypesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxClusterTypeRead(d, m)\n}\n\nfunc resourceNetboxClusterTypeDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationClusterTypesDeleteParams().WithID(id)\n\n\t_, err := api.Virtualization.VirtualizationClusterTypesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationClusterTypesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_cluster_type_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxClusterType_basic(t *testing.T) {\n\ttestSlug := \"clstr_type_data_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_type.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_type.test\", \"slug\", randomSlug),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_cluster_type.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxClusterType_defaultSlug(t *testing.T) {\n\ttestSlug := \"clstr_type_data_default_slug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_type.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_cluster_type.test\", \"slug\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_cluster_type\", &resource.Sweeper{\n\t\tName:         \"netbox_cluster_type\",\n\t\tDependencies: []string{\"netbox_cluster\"},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := virtualization.NewVirtualizationClusterTypesListParams()\n\t\t\tres, err := api.Virtualization.VirtualizationClusterTypesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, clusterType := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*clusterType.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := virtualization.NewVirtualizationClusterTypesDeleteParams().WithID(clusterType.ID)\n\t\t\t\t\t_, err := api.Virtualization.VirtualizationClusterTypesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a cluster type\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_config_context.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxConfigContext() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxConfigContextCreate,\n\t\tRead:   resourceNetboxConfigContextRead,\n\t\tUpdate: resourceNetboxConfigContextUpdate,\n\t\tDelete: resourceNetboxConfigContextDelete,\n\n\t\tDescription: `:meta:subcategory:Extras:From the [official documentation](https://docs.netbox.dev/en/stable/models/extras/configcontext/):\n\n> Context data is made available to devices and/or virtual machines based on their relationships to other objects in NetBox. For example, context data can be associated only with devices assigned to a particular site, or only to virtual machines in a certain cluster.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"weight\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  1000,\n\t\t\t},\n\t\t\t\"data\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringIsJSON,\n\t\t\t},\n\t\t\t\"cluster_groups\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"cluster_types\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"clusters\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"device_types\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"locations\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"platforms\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"regions\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"roles\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"site_groups\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"sites\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"tenant_groups\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"tenants\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"tags\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  nil,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxConfigContextCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableConfigContext{}\n\tdata.Name = strToPtr(d.Get(\"name\").(string))\n\n\tdataJSON, ok := d.GetOk(\"data\")\n\tif ok {\n\t\tvar jsonObj any\n\t\tlocalContextBA := []byte(dataJSON.(string))\n\t\tif err := json.Unmarshal(localContextBA, &jsonObj); err == nil {\n\t\t\tdata.Data = jsonObj\n\t\t}\n\t}\n\tdata.Description = d.Get(\"description\").(string)\n\tdata.ClusterGroups = toInt64List(d.Get(\"cluster_groups\"))\n\tdata.ClusterTypes = toInt64List(d.Get(\"cluster_types\"))\n\tdata.Clusters = toInt64List(d.Get(\"clusters\"))\n\tdata.DeviceTypes = toInt64List(d.Get(\"device_types\"))\n\tdata.Locations = toInt64List(d.Get(\"locations\"))\n\tdata.Platforms = toInt64List(d.Get(\"platforms\"))\n\tdata.Regions = toInt64List(d.Get(\"regions\"))\n\tdata.Roles = toInt64List(d.Get(\"roles\"))\n\tdata.SiteGroups = toInt64List(d.Get(\"site_groups\"))\n\tdata.Sites = toInt64List(d.Get(\"sites\"))\n\tdata.TenantGroups = toInt64List(d.Get(\"tenant_groups\"))\n\tdata.Tenants = toInt64List(d.Get(\"tenants\"))\n\tdata.Tags = toStringList(d.Get(tagsAllKey))\n\tdata.Weight = int64ToPtr(int64(d.Get(\"weight\").(int)))\n\n\tparams := extras.NewExtrasConfigContextsCreateParams().WithData(&data)\n\n\tres, err := api.Extras.ExtrasConfigContextsCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxConfigContextRead(d, m)\n}\n\nfunc resourceNetboxConfigContextRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasConfigContextsReadParams().WithID(id)\n\n\tres, err := api.Extras.ExtrasConfigContextsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasConfigContextsReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"description\", res.GetPayload().Description)\n\td.Set(\"weight\", res.GetPayload().Weight)\n\n\tif res.GetPayload().Data != nil {\n\t\tif jsonArr, err := json.Marshal(res.GetPayload().Data); err == nil {\n\t\t\td.Set(\"data\", string(jsonArr))\n\t\t}\n\t} else {\n\t\td.Set(\"data\", nil)\n\t}\n\n\tclusterGroups := res.GetPayload().ClusterGroups\n\tclusterGroupsSlice := make([]int64, len(clusterGroups))\n\tfor i, v := range clusterGroups {\n\t\tclusterGroupsSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"cluster_groups\", clusterGroupsSlice)\n\n\tclusterTypes := res.GetPayload().ClusterTypes\n\tclusterTypesSlice := make([]int64, len(clusterTypes))\n\tfor i, v := range clusterTypes {\n\t\tclusterTypesSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"cluster_types\", clusterTypesSlice)\n\n\tclusters := res.GetPayload().Clusters\n\tclustersSlice := make([]int64, len(clusters))\n\tfor i, v := range clusters {\n\t\tclustersSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"clusters\", clustersSlice)\n\n\tdeviceTypes := res.GetPayload().DeviceTypes\n\tdeviceTypesSlice := make([]int64, len(deviceTypes))\n\tfor i, v := range deviceTypes {\n\t\tdeviceTypesSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"device_types\", deviceTypesSlice)\n\n\tlocations := res.GetPayload().Locations\n\tlocationsSlice := make([]int64, len(locations))\n\tfor i, v := range locations {\n\t\tlocationsSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"locations\", locationsSlice)\n\n\tplatforms := res.GetPayload().Platforms\n\tplatformsSlice := make([]int64, len(platforms))\n\tfor i, v := range platforms {\n\t\tplatformsSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"platforms\", platformsSlice)\n\n\tregions := res.GetPayload().Regions\n\tregionsSlice := make([]int64, len(regions))\n\tfor i, v := range regions {\n\t\tregionsSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"regions\", regionsSlice)\n\n\troles := res.GetPayload().Roles\n\trolesSlice := make([]int64, len(roles))\n\tfor i, v := range roles {\n\t\trolesSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"roles\", rolesSlice)\n\n\tsiteGroups := res.GetPayload().SiteGroups\n\tsiteGroupsSlice := make([]int64, len(siteGroups))\n\tfor i, v := range siteGroups {\n\t\tsiteGroupsSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"site_groups\", siteGroupsSlice)\n\n\tsites := res.GetPayload().Sites\n\tsitesSlice := make([]int64, len(sites))\n\tfor i, v := range sites {\n\t\tsitesSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"sites\", sitesSlice)\n\n\t// hack since `readTags` mostly deals with nested tags\n\ttags := make([]*models.NestedTag, 0, len(res.GetPayload().Tags))\n\tfor _, tagName := range res.GetPayload().Tags {\n\t\ttags = append(tags, &models.NestedTag{\n\t\t\tName: &tagName,\n\t\t})\n\t}\n\tapi.readTags(d, tags)\n\n\ttenantGroups := res.GetPayload().TenantGroups\n\ttenantGroupsSlice := make([]int64, len(tenantGroups))\n\tfor i, v := range tenantGroups {\n\t\ttenantGroupsSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"tenant_groups\", tenantGroupsSlice)\n\n\ttenants := res.GetPayload().Tenants\n\ttenantsSlice := make([]int64, len(tenants))\n\tfor i, v := range tenants {\n\t\ttenantsSlice[i] = int64(v.ID)\n\t}\n\td.Set(\"tenants\", tenantsSlice)\n\n\treturn nil\n}\n\nfunc resourceNetboxConfigContextUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableConfigContext{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tdataValue, ok := d.GetOk(\"data\")\n\tif ok {\n\t\tvar jsonObj any\n\t\tlocalContextBA := []byte(dataValue.(string))\n\t\tif err := json.Unmarshal(localContextBA, &jsonObj); err == nil {\n\t\t\tdata.Data = jsonObj\n\t\t}\n\t}\n\tdata.Description = d.Get(\"description\").(string)\n\tdata.ClusterGroups = toInt64List(d.Get(\"cluster_groups\"))\n\tdata.ClusterTypes = toInt64List(d.Get(\"cluster_types\"))\n\tdata.Clusters = toInt64List(d.Get(\"clusters\"))\n\tdata.DeviceTypes = toInt64List(d.Get(\"device_types\"))\n\tdata.Locations = toInt64List(d.Get(\"locations\"))\n\tdata.Platforms = toInt64List(d.Get(\"platforms\"))\n\tdata.Regions = toInt64List(d.Get(\"regions\"))\n\tdata.Roles = toInt64List(d.Get(\"roles\"))\n\tdata.SiteGroups = toInt64List(d.Get(\"site_groups\"))\n\tdata.Sites = toInt64List(d.Get(\"sites\"))\n\tdata.TenantGroups = toInt64List(d.Get(\"tenant_groups\"))\n\tdata.Tenants = toInt64List(d.Get(\"tenants\"))\n\tdata.Tags = toStringList(d.Get(tagsAllKey))\n\tdata.Weight = int64ToPtr(int64(d.Get(\"weight\").(int)))\n\n\tparams := extras.NewExtrasConfigContextsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Extras.ExtrasConfigContextsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxConfigContextRead(d, m)\n}\n\nfunc resourceNetboxConfigContextDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasConfigContextsDeleteParams().WithID(id)\n\n\t_, err := api.Extras.ExtrasConfigContextsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_config_context_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxConfigContext_basic(t *testing.T) {\n\ttestSlug := \"config_context_assignments\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_config_context\" \"test\" {\n  name = \"%s\"\n  description = \"test description\"\n  data = jsonencode({\"testkey\" = \"testval\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_context.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_context.test\", \"data\", \"{\\\"testkey\\\":\\\"testval\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_config_context.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxConfigContext_defaultWeight(t *testing.T) {\n\ttestSlug := \"config_context_assignments\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_config_context\" \"test\" {\n  name = \"%s\"\n  data = jsonencode({\"testkey\" = \"testval\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_context.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_context.test\", \"weight\", \"1000\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxConfigContext_assignments(t *testing.T) {\n\ttestSlug := \"config_context_assignments\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\nresource \"netbox_tenant_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n  group_id = netbox_tenant_group.test.id\n}\n\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n  group_id = netbox_site_group.test.id\n}\n\nresource \"netbox_region\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_group\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  site_id = netbox_site.test.id\n  cluster_group_id = netbox_cluster_group.test.id\n}\n\nresource \"netbox_location\" \"test\" {\n    name = \"%[1]s\"\n    site_id =netbox_site.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n# Untested: cluster_groups, regions, site_groups, tenant_groups\nresource \"netbox_config_context\" \"test\" {\n  name = \"%[1]s\"\n  data = jsonencode({\"testkey\" = \"testval\"})\n  regions = [netbox_region.test.id]\n  tenant_groups = [netbox_tenant_group.test.id]\n  tenants = [netbox_tenant.test.id]\n  platforms = [netbox_platform.test.id]\n  sites = [netbox_site.test.id]\n  site_groups = [netbox_site_group.test.id]\n  cluster_types = [netbox_cluster_type.test.id]\n  cluster_groups = [netbox_cluster_group.test.id]\n  clusters = [netbox_cluster.test.id]\n  locations = [netbox_location.test.id]\n  roles = [netbox_device_role.test.id]\n  tags = [netbox_tag.test.name]\n  device_types = [netbox_device_type.test.id]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_context.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"regions.0\", \"netbox_region.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"tenant_groups.0\", \"netbox_tenant_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"tenants.0\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"platforms.0\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"sites.0\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"site_groups.0\", \"netbox_site_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"cluster_types.0\", \"netbox_cluster_type.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"cluster_groups.0\", \"netbox_cluster_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"clusters.0\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"locations.0\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"roles.0\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"tags.0\", \"netbox_tag.test\", \"name\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_config_context.test\", \"device_types.0\", \"netbox_device_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_config_context\", &resource.Sweeper{\n\t\tName:         \"netbox_config_context\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := extras.NewExtrasConfigContextsListParams()\n\t\t\tres, err := api.Extras.ExtrasConfigContextsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, configContext := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*configContext.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := extras.NewExtrasConfigContextsDeleteParams().WithID(configContext.ID)\n\t\t\t\t\t_, err := api.Extras.ExtrasConfigContextsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a config context\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_config_template.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxConfigTemplate() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxConfigTemplateCreate,\n\t\tReadContext:   resourceNetboxConfigTemplateRead,\n\t\tUpdateContext: resourceNetboxConfigTemplateUpdate,\n\t\tDeleteContext: resourceNetboxConfigTemplateDelete,\n\n\t\tDescription: `:meta:subcategory:Extras:From the [official documentation](https://docs.netbox.dev/en/stable/models/extras/configtemplate/):\n\n> Configuration templates can be used to render device configurations from context data. Templates are written in the Jinja2 language and can be associated with devices roles, platforms, and/or individual devices.\n\n> Context data is made available to devices and/or virtual machines based on their relationships to other objects in NetBox. For example, context data can be associated only with devices assigned to a particular site, or only to virtual machines in a certain cluster.`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"template_code\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"environment_params\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tDefault:      \"{}\",\n\t\t\t\tValidateFunc: validation.StringIsJSON,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxConfigTemplateCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\ttemplateCode := d.Get(\"template_code\").(string)\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tdata := models.WritableConfigTemplate{\n\t\tName:         &name,\n\t\tDescription:  description,\n\t\tTemplateCode: &templateCode,\n\t\tTags:         tags,\n\t}\n\n\t// Unmarshal environment_params and add it to data if valid\n\tenvironmentParamsJSON, ok := d.GetOk(\"environment_params\")\n\n\tif ok {\n\t\tvar environmentParams any\n\t\terr := json.Unmarshal([]byte(environmentParamsJSON.(string)), &environmentParams)\n\t\tif err != nil {\n\t\t\treturn diag.FromErr(err)\n\t\t}\n\n\t\tdata.EnvironmentParams = environmentParams\n\t}\n\n\tparams := extras.NewExtrasConfigTemplatesCreateParams().WithData(&data)\n\n\tres, err := api.Extras.ExtrasConfigTemplatesCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn diags\n}\n\nfunc resourceNetboxConfigTemplateRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tvar diags diag.Diagnostics\n\n\tparams := extras.NewExtrasConfigTemplatesReadParams().WithID(id)\n\n\tres, err := api.Extras.ExtrasConfigTemplatesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasConfigTemplatesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\ttmpl := res.GetPayload()\n\n\td.Set(\"name\", tmpl.Name)\n\td.Set(\"description\", tmpl.Description)\n\td.Set(\"template_code\", tmpl.TemplateCode)\n\n\tif tmpl.EnvironmentParams != nil {\n\t\tenvironmentParamsJSON, err := json.Marshal(tmpl.EnvironmentParams)\n\t\tif err != nil {\n\t\t\treturn diag.FromErr(err)\n\t\t}\n\n\t\td.Set(\"environment_params\", string(environmentParamsJSON))\n\t} else {\n\t\td.Set(\"environment_params\", \"{}\")\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxConfigTemplateUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\ttemplateCode := d.Get(\"template_code\").(string)\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tdata := models.WritableConfigTemplate{\n\t\tName:         &name,\n\t\tDescription:  description,\n\t\tTemplateCode: &templateCode,\n\t\tTags:         tags,\n\t}\n\n\t// Unmarshal environment_params and add it to data if valid\n\tenvironmentParamsJSON, ok := d.GetOk(\"environment_params\")\n\n\tif ok {\n\t\tvar environmentParams any\n\t\terr := json.Unmarshal([]byte(environmentParamsJSON.(string)), &environmentParams)\n\t\tif err != nil {\n\t\t\treturn diag.FromErr(err)\n\t\t}\n\n\t\tdata.EnvironmentParams = environmentParams\n\t}\n\n\tparams := extras.NewExtrasConfigTemplatesUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Extras.ExtrasConfigTemplatesUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxConfigTemplateDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasConfigTemplatesDeleteParams().WithID(id)\n\n\t_, err := api.Extras.ExtrasConfigTemplatesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasConfigTemplatesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_config_template_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc TestAccNetboxConfigTemplate_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"config_template\")\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_config_template\" \"test\" {\n\tname = \"%[1]s\"\n\tdescription = \"%[1]s description\"\n\ttemplate_code = \"hostname {{ name }}\"\n\tenvironment_params = jsonencode({\"name\" = \"my-hostname\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test\", \"description\", fmt.Sprintf(\"%s description\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test\", \"template_code\", \"hostname {{ name }}\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test\", \"environment_params\", \"{\\\"name\\\":\\\"my-hostname\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_config_template\" \"test\" {\n\tname = \"%[1]s\"\n\tdescription = \"%[1]s description\"\n\ttemplate_code = \"hostname {{ new_var }}\"\n\tenvironment_params = jsonencode({\"new_var\" = \"my-hostname-2\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test\", \"description\", fmt.Sprintf(\"%s description\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test\", \"template_code\", \"hostname {{ new_var }}\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test\", \"environment_params\", \"{\\\"new_var\\\":\\\"my-hostname-2\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_config_template.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxConfigTemplate_tags(t *testing.T) {\n\ttestName := testAccGetTestName(\"config_template_tags\")\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVrfTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_config_template\" \"test_tags\" {\n  name = \"%[1]s\"\n  template_code = \"hostname test\"\n  tags = [netbox_tag.test_a.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test_tags\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test_tags\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test_tags\", \"tags.0\", testName+\"a\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVrfTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_config_template\" \"test_tags\" {\n  name = \"%[1]s\"\n  template_code = \"hostname test\"\n  tags = [netbox_tag.test_a.name, netbox_tag.test_b.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test_tags\", \"tags.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test_tags\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test_tags\", \"tags.1\", testName+\"b\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVrfTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_config_template\" \"test_tags\" {\n  name = \"%s\"\n  template_code = \"hostname test\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_config_template.test_tags\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_config_template\", &resource.Sweeper{\n\t\tName:         \"netbox_config_template\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := extras.NewExtrasConfigTemplatesListParams()\n\t\t\tres, err := api.Extras.ExtrasConfigTemplatesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tmpl := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*tmpl.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := extras.NewExtrasConfigTemplatesDeleteParams().WithID(tmpl.ID)\n\t\t\t\t\t_, err := api.Extras.ExtrasConfigTemplatesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a config template\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_contact.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/go-openapi/strfmt\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxContact() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxContactCreate,\n\t\tRead:   resourceNetboxContactRead,\n\t\tUpdate: resourceNetboxContactUpdate,\n\t\tDelete: resourceNetboxContactDelete,\n\n\t\tDescription: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contacts_1):\n\n> A contact should represent an individual or permanent point of contact. Each contact must define a name, and may optionally include a title, phone number, email address, and related details.\n>\n> Contacts are reused for assignments, so each unique contact must be created only once and can be assigned to any number of NetBox objects, and there is no limit to the number of assigned contacts an object may have. Most core objects in NetBox can have contacts assigned to them.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"email\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"phone\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"link\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxContactCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tphone := d.Get(\"phone\").(string)\n\temail := d.Get(\"email\").(string)\n\tlink := d.Get(\"link\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tgroupID := int64(d.Get(\"group_id\").(int))\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tdata := &models.WritableContact{}\n\n\tdata.Name = &name\n\tdata.Tags = tags\n\tdata.Phone = phone\n\tdata.Email = strfmt.Email(email)\n\tdata.Link = strfmt.URI(link)\n\tdata.Description = description\n\tif groupID != 0 {\n\t\tdata.Group = &groupID\n\t}\n\n\tparams := tenancy.NewTenancyContactsCreateParams().WithData(data)\n\n\tres, err := api.Tenancy.TenancyContactsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxContactRead(d, m)\n}\n\nfunc resourceNetboxContactRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyContactsReadParams().WithID(id)\n\n\tres, err := api.Tenancy.TenancyContactsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyContactsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"phone\", res.GetPayload().Phone)\n\td.Set(\"email\", res.GetPayload().Email)\n\td.Set(\"link\", res.GetPayload().Link)\n\td.Set(\"description\", res.GetPayload().Description)\n\tif res.GetPayload().Group != nil {\n\t\td.Set(\"group_id\", res.GetPayload().Group.ID)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxContactUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableContact{}\n\n\tname := d.Get(\"name\").(string)\n\tphone := d.Get(\"phone\").(string)\n\temail := d.Get(\"email\").(string)\n\tlink := d.Get(\"link\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tgroupID := int64(d.Get(\"group_id\").(int))\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tdata.Name = &name\n\tdata.Tags = tags\n\tdata.Phone = phone\n\tdata.Email = strfmt.Email(email)\n\tdata.Link = strfmt.URI(link)\n\tdata.Description = description\n\tif groupID != 0 {\n\t\tdata.Group = &groupID\n\t}\n\n\tparams := tenancy.NewTenancyContactsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Tenancy.TenancyContactsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxContactRead(d, m)\n}\n\nfunc resourceNetboxContactDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyContactsDeleteParams().WithID(id)\n\n\t_, err := api.Tenancy.TenancyContactsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyContactsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_contact_assignment.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxContactAssignmentPriorityOptions = []string{\"primary\", \"secondary\", \"tertiary\", \"inactive\"}\n\nfunc resourceNetboxContactAssignment() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxContactAssignmentCreate,\n\t\tRead:   resourceNetboxContactAssignmentRead,\n\t\tUpdate: resourceNetboxContactAssignmentUpdate,\n\t\tDelete: resourceNetboxContactAssignmentDelete,\n\n\t\tDescription: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts#contactassignments_1):\n\n> Much like tenancy, contact assignment enables you to track ownership of resources modeled in NetBox.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"content_type\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"object_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"contact_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"priority\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxContactAssignmentPriorityOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxContactAssignmentPriorityOptions),\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxContactAssignmentCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tcontentType := d.Get(\"content_type\").(string)\n\tobjectID := int64(d.Get(\"object_id\").(int))\n\tcontactID := int64(d.Get(\"contact_id\").(int))\n\troleID := int64(d.Get(\"role_id\").(int))\n\tpriority := d.Get(\"priority\").(string)\n\n\tdata := &models.WritableContactAssignment{}\n\n\tdata.ObjectType = contentType\n\tdata.ObjectID = &objectID\n\tdata.Contact = &contactID\n\tdata.Role = &roleID\n\tdata.Priority = priority\n\n\tparams := tenancy.NewTenancyContactAssignmentsCreateParams().WithData(data)\n\n\tres, err := api.Tenancy.TenancyContactAssignmentsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxContactAssignmentRead(d, m)\n}\n\nfunc resourceNetboxContactAssignmentRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyContactAssignmentsReadParams().WithID(id)\n\n\tres, err := api.Tenancy.TenancyContactAssignmentsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyContactAssignmentsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"content_type\", res.GetPayload().ObjectType)\n\n\tif res.GetPayload().ObjectID != nil {\n\t\td.Set(\"object_id\", res.GetPayload().ObjectID)\n\t}\n\tif res.GetPayload().Contact != nil {\n\t\td.Set(\"contact_id\", res.GetPayload().Contact.ID)\n\t}\n\tif res.GetPayload().Role != nil {\n\t\td.Set(\"role_id\", res.GetPayload().Role.ID)\n\t}\n\tif res.GetPayload().Priority != nil {\n\t\td.Set(\"priority\", res.GetPayload().Priority.Value)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxContactAssignmentUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableContactAssignment{}\n\n\tcontentType := d.Get(\"content_type\").(string)\n\tobjectID := int64(d.Get(\"object_id\").(int))\n\tcontactID := int64(d.Get(\"contact_id\").(int))\n\troleID := int64(d.Get(\"role_id\").(int))\n\tpriority := d.Get(\"priority\").(string)\n\n\tdata.ObjectType = contentType\n\tif objectID != 0 {\n\t\tdata.ObjectID = &objectID\n\t}\n\tif contactID != 0 {\n\t\tdata.Contact = &contactID\n\t}\n\tif roleID != 0 {\n\t\tdata.Role = &roleID\n\t}\n\tdata.Priority = priority\n\n\tparams := tenancy.NewTenancyContactAssignmentsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Tenancy.TenancyContactAssignmentsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxContactAssignmentRead(d, m)\n}\n\nfunc resourceNetboxContactAssignmentDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyContactAssignmentsDeleteParams().WithID(id)\n\n\t_, err := api.Tenancy.TenancyContactAssignmentsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyContactAssignmentsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_contact_assignment_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxContactAssignment_basic(t *testing.T) {\n\ttestSlug := \"contactassign\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n}\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n}\nresource \"netbox_contact\" \"test\" {\n  name = \"%[1]s\"\n}\nresource \"netbox_contact_role\" \"test\" {\n  name = \"%[1]s\"\n}\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\nresource \"netbox_contact_assignment\" \"test\" {\n  content_type = \"dcim.device\"\n  object_id = netbox_device.test.id\n  contact_id = netbox_contact.test.id\n  role_id = netbox_contact_role.test.id\n  priority = \"primary\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact_assignment.test\", \"content_type\", \"dcim.device\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_contact_assignment.test\", \"object_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_contact_assignment.test\", \"contact_id\", \"netbox_contact.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_contact_assignment.test\", \"role_id\", \"netbox_contact_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact_assignment.test\", \"priority\", \"primary\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_contact_assignment.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_contact_assignment\", &resource.Sweeper{\n\t\tName:         \"netbox_contact_assignment\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := tenancy.NewTenancyContactAssignmentsListParams()\n\t\t\tres, err := api.Tenancy.TenancyContactAssignmentsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, contactassignment := range res.GetPayload().Results {\n\t\t\t\tdeleteParams := tenancy.NewTenancyContactAssignmentsDeleteParams().WithID(contactassignment.ID)\n\t\t\t\t_, err := api.Tenancy.TenancyContactAssignmentsDelete(deleteParams, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tlog.Print(\"[DEBUG] Deleted a contact assignment\")\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_contact_group.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxContactGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxContactGroupCreate,\n\t\tRead:   resourceNetboxContactGroupRead,\n\t\tUpdate: resourceNetboxContactGroupUpdate,\n\t\tDelete: resourceNetboxContactGroupDelete,\n\n\t\tDescription: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contact-groups):\n\n> Contacts can be grouped arbitrarily into a recursive hierarchy, and a contact can be assigned to a group at any level within the hierarchy.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxContactGroupCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparentID := int64(d.Get(\"parent_id\").(int))\n\tdescription := d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata := &models.WritableContactGroup{}\n\tdata.Name = &name\n\tdata.Slug = &slug\n\tdata.Description = description\n\tdata.Tags = []*models.NestedTag{}\n\n\tif parentID != 0 {\n\t\tdata.Parent = &parentID\n\t}\n\n\tparams := tenancy.NewTenancyContactGroupsCreateParams().WithData(data)\n\n\tres, err := api.Tenancy.TenancyContactGroupsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxContactGroupRead(d, m)\n}\n\nfunc resourceNetboxContactGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := tenancy.NewTenancyContactGroupsReadParams().WithID(id)\n\n\tres, err := api.Tenancy.TenancyContactGroupsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyContactGroupsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"description\", res.GetPayload().Description)\n\tif res.GetPayload().Parent != nil {\n\t\td.Set(\"parent\", res.GetPayload().Parent.ID)\n\t}\n\treturn nil\n}\n\nfunc resourceNetboxContactGroupUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableContactGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tparentID := int64(d.Get(\"parent_id\").(int))\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.Description = description\n\tdata.Tags = []*models.NestedTag{}\n\n\tif parentID != 0 {\n\t\tdata.Parent = &parentID\n\t}\n\tparams := tenancy.NewTenancyContactGroupsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Tenancy.TenancyContactGroupsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxContactGroupRead(d, m)\n}\n\nfunc resourceNetboxContactGroupDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyContactGroupsDeleteParams().WithID(id)\n\n\t_, err := api.Tenancy.TenancyContactGroupsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_contact_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxContactGroup_basic(t *testing.T) {\n\ttestSlug := \"t_grp_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_contact_group\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact_group.test\", \"name\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_contact_group.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxContactGroup_defaultSlug(t *testing.T) {\n\ttestSlug := \"contactgrp_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_contact_group\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact_group.test\", \"name\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_contact_group\", &resource.Sweeper{\n\t\tName:         \"netbox_contact_group\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := tenancy.NewTenancyContactGroupsListParams()\n\t\t\tres, err := api.Tenancy.TenancyContactGroupsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, contactGroup := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*contactGroup.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := tenancy.NewTenancyContactGroupsDeleteParams().WithID(contactGroup.ID)\n\t\t\t\t\t_, err := api.Tenancy.TenancyContactGroupsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a contact group\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_contact_role.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxContactRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxContactRoleCreate,\n\t\tRead:   resourceNetboxContactRoleRead,\n\t\tUpdate: resourceNetboxContactRoleUpdate,\n\t\tDelete: resourceNetboxContactRoleDelete,\n\n\t\tDescription: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contactroles):\n\n> A contact role defines the relationship of a contact to an assigned object. For example, you might define roles for administrative, operational, and emergency contacts`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxContactRoleCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tdata := &models.ContactRole{}\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Name = &name\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := tenancy.NewTenancyContactRolesCreateParams().WithData(data)\n\n\tres, err := api.Tenancy.TenancyContactRolesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxContactRoleRead(d, m)\n}\n\nfunc resourceNetboxContactRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyContactRolesReadParams().WithID(id)\n\n\tres, err := api.Tenancy.TenancyContactRolesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyContactRolesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tcontactrole := res.GetPayload()\n\td.Set(\"name\", contactrole.Name)\n\td.Set(\"slug\", contactrole.Slug)\n\n\treturn nil\n}\n\nfunc resourceNetboxContactRoleUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.ContactRole{}\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Name = &name\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := tenancy.NewTenancyContactRolesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Tenancy.TenancyContactRolesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxContactRoleRead(d, m)\n}\n\nfunc resourceNetboxContactRoleDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyContactRolesDeleteParams().WithID(id)\n\n\t_, err := api.Tenancy.TenancyContactRolesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyContactRolesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_contact_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxContactRole_basic(t *testing.T) {\n\ttestSlug := \"contactrole\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_contact_role\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact_role.test\", \"name\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_contact_role.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_contact_role\", &resource.Sweeper{\n\t\tName:         \"netbox_contact_role\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := tenancy.NewTenancyContactRolesListParams()\n\t\t\tres, err := api.Tenancy.TenancyContactRolesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, contactrole := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*contactrole.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := tenancy.NewTenancyContactRolesDeleteParams().WithID(contactrole.ID)\n\t\t\t\t\t_, err := api.Tenancy.TenancyContactRolesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a contact role\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_contact_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxContactTagDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_tag\" \"test_b\" {\n  name = \"%[1]sb\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxContact_basic(t *testing.T) {\n\ttestSlug := \"contact_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_contact\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test\", \"name\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_contact\" \"test\" {\n  name        = \"%s\"\n  email       = \"test@test.com\"\n  phone       = \"123-123123\"\n  link        = \"https://example.com\"\n  description = \"desc\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test\", \"email\", \"test@test.com\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test\", \"phone\", \"123-123123\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test\", \"link\", \"https://example.com\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test\", \"description\", \"desc\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_contact.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxContact_tags(t *testing.T) {\n\ttestSlug := \"contact_tags\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxContactTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_contact\" \"test_tags\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test_tags\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test_tags\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test_tags\", \"tags.0\", testName+\"a\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxContactTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_contact\" \"test_tags\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name, netbox_tag.test_b.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test_tags\", \"tags.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test_tags\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test_tags\", \"tags.1\", testName+\"b\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxContactTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_contact\" \"test_tags\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_contact.test_tags\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_contact\", &resource.Sweeper{\n\t\tName:         \"netbox_contact\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := tenancy.NewTenancyContactsListParams()\n\t\t\tres, err := api.Tenancy.TenancyContactsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, contact := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*contact.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := tenancy.NewTenancyContactsDeleteParams().WithID(contact.ID)\n\t\t\t\t\t_, err := api.Tenancy.TenancyContactsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a contact\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_custom_field.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceCustomField() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxCustomFieldCreate,\n\t\tRead:   resourceNetboxCustomFieldRead,\n\t\tUpdate: resourceNetboxCustomFieldUpdate,\n\t\tDelete: resourceNetboxCustomFieldDelete,\n\n\t\tDescription: `:meta:subcategory:Extras:From the [official documentation](https://docs.netbox.dev/en/stable/customization/custom-fields/#custom-fields):\n\n> Each model in NetBox is represented in the database as a discrete table, and each attribute of a model exists as a column within its table. For example, sites are stored in the dcim_site table, which has columns named name, facility, physical_address, and so on. As new attributes are added to objects throughout the development of NetBox, tables are expanded to include new rows.\n>\n> However, some users might want to store additional object attributes that are somewhat esoteric in nature, and that would not make sense to include in the core NetBox database schema. For instance, suppose your organization needs to associate each device with a ticket number correlating it with an internal support system record. This is certainly a legitimate use for NetBox, but it's not a common enough need to warrant including a field for every NetBox installation. Instead, you can create a custom field to hold this data.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\n\t\t\t\t\tmodels.CustomFieldTypeValueText,\n\t\t\t\t\tmodels.CustomFieldTypeValueInteger,\n\t\t\t\t\tmodels.CustomFieldTypeValueBoolean,\n\t\t\t\t\tmodels.CustomFieldTypeValueDate,\n\t\t\t\t\tmodels.CustomFieldTypeValueURL,\n\t\t\t\t\tmodels.CustomFieldTypeValueSelect,\n\t\t\t\t\tmodels.CustomFieldTypeValueMultiselect,\n\t\t\t\t\tmodels.CustomFieldTypeValueJSON,\n\t\t\t\t}, false),\n\t\t\t},\n\t\t\t\"content_types\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tRequired: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t\tSet: schema.HashString,\n\t\t\t},\n\t\t\t\"weight\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t\tDefaultFunc: func() (interface{}, error) {\n\t\t\t\t\treturn 100, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"default\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"group_name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"required\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"validation_maximum\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"validation_minimum\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"validation_regex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"choice_set_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxCustomFieldUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := &models.WritableCustomField{\n\t\tName:            strToPtr(d.Get(\"name\").(string)),\n\t\tType:            d.Get(\"type\").(string),\n\t\tDefault:         d.Get(\"default\").(string),\n\t\tDescription:     d.Get(\"description\").(string),\n\t\tGroupName:       d.Get(\"group_name\").(string),\n\t\tLabel:           d.Get(\"label\").(string),\n\t\tRequired:        d.Get(\"required\").(bool),\n\t\tValidationRegex: d.Get(\"validation_regex\").(string),\n\t\tWeight:          int64ToPtr(int64(d.Get(\"weight\").(int))),\n\t}\n\n\tchoiceSet, ok := d.GetOk(\"choice_set_id\")\n\tif ok {\n\t\tdata.ChoiceSet = int64ToPtr(int64(choiceSet.(int)))\n\t}\n\n\tctypes, ok := d.GetOk(\"content_types\")\n\tif ok {\n\t\tctypes := ctypes.(*schema.Set).List()\n\t\tobjectTypes := make([]string, 0, len(ctypes))\n\t\tfor _, t := range ctypes {\n\t\t\tobjectTypes = append(objectTypes, t.(string))\n\t\t}\n\t\tdata.ObjectTypes = objectTypes\n\t}\n\n\tvmax, ok := d.GetOk(\"validation_maximum\")\n\tif ok {\n\t\tdata.ValidationMaximum = int64ToPtr(int64(vmax.(int)))\n\t}\n\tvmin, ok := d.GetOk(\"validation_minimum\")\n\tif ok {\n\t\tdata.ValidationMinimum = int64ToPtr(int64(vmin.(int)))\n\t}\n\n\tparams := extras.NewExtrasCustomFieldsUpdateParams().WithID(id).WithData(data)\n\tres, err := api.Extras.ExtrasCustomFieldsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxCustomFieldRead(d, m)\n}\n\nfunc resourceNetboxCustomFieldCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := &models.WritableCustomField{\n\t\tName:            strToPtr(d.Get(\"name\").(string)),\n\t\tType:            d.Get(\"type\").(string),\n\t\tDefault:         d.Get(\"default\").(string),\n\t\tDescription:     d.Get(\"description\").(string),\n\t\tGroupName:       d.Get(\"group_name\").(string),\n\t\tLabel:           d.Get(\"label\").(string),\n\t\tRequired:        d.Get(\"required\").(bool),\n\t\tValidationRegex: d.Get(\"validation_regex\").(string),\n\t\tWeight:          int64ToPtr(int64(d.Get(\"weight\").(int))),\n\t}\n\n\tchoiceSet, ok := d.GetOk(\"choice_set_id\")\n\tif ok {\n\t\tdata.ChoiceSet = int64ToPtr(int64(choiceSet.(int)))\n\t}\n\n\tctypes, ok := d.GetOk(\"content_types\")\n\tif ok {\n\t\tctypes := ctypes.(*schema.Set).List()\n\t\tobjectTypes := make([]string, 0, len(ctypes))\n\t\tfor _, t := range ctypes {\n\t\t\tobjectTypes = append(objectTypes, t.(string))\n\t\t}\n\t\tdata.ObjectTypes = objectTypes\n\t}\n\n\tvmax, ok := d.GetOk(\"validation_maximum\")\n\tif ok {\n\t\tdata.ValidationMaximum = int64ToPtr(int64(vmax.(int)))\n\t}\n\tvmin, ok := d.GetOk(\"validation_minimum\")\n\tif ok {\n\t\tdata.ValidationMinimum = int64ToPtr(int64(vmin.(int)))\n\t}\n\n\tparams := extras.NewExtrasCustomFieldsCreateParams().WithData(data)\n\n\tres, err := api.Extras.ExtrasCustomFieldsCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxCustomFieldRead(d, m)\n}\n\nfunc resourceNetboxCustomFieldRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasCustomFieldsReadParams().WithID(id)\n\tres, err := api.Extras.ExtrasCustomFieldsRead(params, nil)\n\tif err != nil {\n\t\terrapi, ok := err.(*extras.ExtrasCustomFieldsReadDefault)\n\t\tif !ok {\n\t\t\treturn err\n\t\t}\n\t\terrorcode := errapi.Code()\n\t\tif errorcode == 404 {\n\t\t\td.SetId(\"\")\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\tcustomField := res.GetPayload()\n\td.Set(\"name\", customField.Name)\n\td.Set(\"type\", *customField.Type.Value)\n\n\td.Set(\"content_types\", customField.ObjectTypes)\n\n\tchoiceSet := customField.ChoiceSet\n\tif choiceSet != nil {\n\t\td.Set(\"choice_set_id\", customField.ChoiceSet.ID)\n\t}\n\n\td.Set(\"weight\", customField.Weight)\n\tif customField.Default != nil {\n\t\td.Set(\"default\", customField.Default)\n\t}\n\n\td.Set(\"description\", customField.Description)\n\td.Set(\"group_name\", customField.GroupName)\n\td.Set(\"label\", customField.Label)\n\td.Set(\"required\", customField.Required)\n\n\td.Set(\"validation_maximum\", customField.ValidationMaximum)\n\td.Set(\"validation_minimum\", customField.ValidationMinimum)\n\td.Set(\"validation_regex\", customField.ValidationRegex)\n\n\treturn nil\n}\n\nfunc resourceNetboxCustomFieldDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasCustomFieldsDeleteParams().WithID(id)\n\t_, err := api.Extras.ExtrasCustomFieldsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasCustomFieldsDeleteDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_custom_field_choice_set.go",
    "content": "package netbox\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxCustomFieldChoiceSetBaseChoicesOptions = []string{\"IATA\", \"ISO_3166\", \"UN_LOCODE\"}\n\nfunc resourceNetboxCustomFieldChoiceSet() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxCustomFieldChoiceSetCreate,\n\t\tRead:   resourceNetboxCustomFieldChoiceSetRead,\n\t\tUpdate: resourceNetboxCustomFieldChoiceSetUpdate,\n\t\tDelete: resourceNetboxCustomFieldChoiceSetDelete,\n\n\t\tDescription: `:meta:subcategory:Extras:From the [official documentation](https://docs.netbox.dev/en/stable/models/extras/customfieldchoiceset/):\n\nSingle- and multi-selection custom fields must define a set of valid choices from which the user may choose when defining the field value. These choices are defined as sets that may be reused among multiple custom fields.\n\nA choice set must define a base choice set and/or a set of arbitrary extra choices.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"base_choices\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxCustomFieldChoiceSetBaseChoicesOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxCustomFieldChoiceSetBaseChoicesOptions),\n\t\t\t\tAtLeastOneOf: []string{\"base_choices\", \"extra_choices\"},\n\t\t\t},\n\t\t\t\"extra_choices\": {\n\t\t\t\tType:        schema.TypeList,\n\t\t\t\tDescription: \"This length of the inner lists must be exactly two, where the first value is the value of a choice and the second value is the label of the choice.\",\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeList,\n\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"base_choices\", \"extra_choices\"},\n\t\t\t\t//\t\t\t\tValidateFunc: func (i interface{}, k string) (warnings []string, _errors []error) {\n\t\t\t\t//\t// Outer list length must be > 0\n\t\t\t\t//\textraChoiceListList := i.([][]string)\n\t\t\t\t//\tif len(extraChoiceListList) == 0 {\n\t\t\t\t//\t\treturn nil, []error{errors.New(\"length of list must be > 0\")}\n\t\t\t\t//\t}\n\t\t\t\t//\n\t\t\t\t//\t// Inner list length must be exactly 2\n\t\t\t\t//\tfor _, innerList := range extraChoiceListList {\n\t\t\t\t//\t\tif len(innerList) != 2 {\n\t\t\t\t//\t\t\treturn nil, []error{errors.New(\"length of list must be > 0\")}\n\t\t\t\t//\t\t}\n\t\t\t\t//\t}\n\t\t\t\t//\n\t\t\t\t//\treturn warnings, _errors\n\t\t\t\t//},\n\t\t\t},\n\t\t\t\"order_alphabetically\": {\n\t\t\t\tType:        schema.TypeBool,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"experimental\",\n\t\t\t\tDefault:     false,\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxCustomFieldChoiceSetCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tdata := models.CustomFieldChoiceSet{\n\t\tName: &name,\n\t}\n\n\tdata.Description = getOptionalStr(d, \"description\", false)\n\n\tvar extraChoiceListList [][]string\n\n\textraChoices, ok := d.GetOk(\"extra_choices\")\n\tif ok {\n\t\tfor _, innerList := range extraChoices.([]interface{}) {\n\t\t\ttmp := innerList.([]interface{})\n\t\t\tif len(tmp) != 2 {\n\t\t\t\treturn errors.New(\"length of inner lists must be exactly two for custom field choice sets\")\n\t\t\t}\n\t\t\textraChoiceListList = append(extraChoiceListList, []string{tmp[0].(string), tmp[1].(string)})\n\t\t}\n\t\tdata.ExtraChoices = extraChoiceListList\n\t}\n\n\tparams := extras.NewExtrasCustomFieldChoiceSetsCreateParams().WithData(&data)\n\n\tres, err := api.Extras.ExtrasCustomFieldChoiceSetsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxCustomFieldChoiceSetRead(d, m)\n}\n\nfunc resourceNetboxCustomFieldChoiceSetRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasCustomFieldChoiceSetsReadParams().WithID(id)\n\n\tres, err := api.Extras.ExtrasCustomFieldChoiceSetsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasCustomFieldChoiceSetsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tchoiceSet := res.GetPayload()\n\n\td.Set(\"name\", choiceSet.Name)\n\n\tif choiceSet.Description != \"\" {\n\t\td.Set(\"description\", choiceSet.Description)\n\t} else {\n\t\td.Set(\"description\", nil)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxCustomFieldChoiceSetUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tname := d.Get(\"name\").(string)\n\n\tdata := models.CustomFieldChoiceSet{\n\t\tName: &name,\n\t}\n\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\n\tvar extraChoiceListList [][]string\n\n\textraChoices, ok := d.GetOk(\"extra_choices\")\n\tif ok {\n\t\tfor _, innerList := range extraChoices.([]interface{}) {\n\t\t\ttmp := innerList.([]interface{})\n\t\t\tif len(tmp) != 2 {\n\t\t\t\treturn errors.New(\"length of inner lists must be exactly two for custom field choice sets\")\n\t\t\t}\n\t\t\textraChoiceListList = append(extraChoiceListList, []string{tmp[0].(string), tmp[1].(string)})\n\t\t}\n\t\tdata.ExtraChoices = extraChoiceListList\n\t}\n\n\tparams := extras.NewExtrasCustomFieldChoiceSetsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Extras.ExtrasCustomFieldChoiceSetsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxCustomFieldChoiceSetRead(d, m)\n}\n\nfunc resourceNetboxCustomFieldChoiceSetDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasCustomFieldChoiceSetsDeleteParams().WithID(id)\n\n\t_, err := api.Extras.ExtrasCustomFieldChoiceSetsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasCustomFieldChoiceSetsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_custom_field_choice_set_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxCustomFieldChoiceSet_basic(t *testing.T) {\n\ttestSlug := \"cfields_choiceset\"\n\ttestName := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field_choice_set\" \"test\" {\n  name        = \"%s\"\n  description = \"foo\"\n  extra_choices = [\n    [\"choice1\", \"label1\"], # label and choice are different\n    [\"choice2\", \"choice2\"]  # label and choice are the same\n  ]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field_choice_set.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field_choice_set.test\", \"description\", \"foo\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field_choice_set.test\", \"extra_choices.0.0\", \"choice1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field_choice_set.test\", \"extra_choices.0.1\", \"label1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field_choice_set.test\", \"extra_choices.1.0\", \"choice2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field_choice_set.test\", \"extra_choices.1.1\", \"choice2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxCustomFieldChoiceSet_listlength(t *testing.T) {\n\ttestSlug := \"cfields_choiceset_length\"\n\ttestName := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field_choice_set\" \"test\" {\n  name        = \"%s\"\n  description = \"foo\"\n  extra_choices = [\n    [\"choice1\", \"label1\", \"toolong\"]\n  ]\n}`, testName),\n\t\t\t\tExpectError: regexp.MustCompile(\"length of inner lists must be exactly two for custom field choice sets\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field_choice_set\" \"test\" {\n  name        = \"%s\"\n  description = \"foo\"\n  extra_choices = [\n    [\"choice1\"]\n  ]\n}`, testName),\n\t\t\t\tExpectError: regexp.MustCompile(\"length of inner lists must be exactly two for custom field choice sets\"),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_custom_field_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxCustomField_basic(t *testing.T) {\n\ttestSlug := \"custom_fields_basic\"\n\ttestName := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name = \"%s\"\n  type = \"text\"\n  content_types = [\"virtualization.vminterface\"]\n  weight = 100\n  default = \"red\"\n  validation_regex = \"^.*$\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"type\", \"text\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttr(\"netbox_custom_field.test\", \"content_types.*\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"weight\", \"100\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"default\", \"red\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"validation_regex\", \"^.*$\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxCustomField_json(t *testing.T) {\n\ttestSlug := \"custom_fields_json\"\n\ttestName := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name = \"%s\"\n  type = \"json\"\n  content_types = [\"virtualization.vminterface\"]\n  group_name = \"mygroup\"\n  weight = 100\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"type\", \"json\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttr(\"netbox_custom_field.test\", \"content_types.*\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"group_name\", \"mygroup\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"weight\", \"100\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxCustomField_integer(t *testing.T) {\n\ttestSlug := \"custom_fields_integer\"\n\ttestName := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name = \"%s\"\n  type = \"integer\"\n  content_types = [\"virtualization.vminterface\"]\n  group_name = \"mygroup\"\n  weight = 100\n  validation_maximum = 1000\n  validation_minimum = 10\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"type\", \"integer\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttr(\"netbox_custom_field.test\", \"content_types.*\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"group_name\", \"mygroup\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"weight\", \"100\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"validation_maximum\", \"1000\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"validation_minimum\", \"10\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxCustomField_select(t *testing.T) {\n\ttestSlug := \"custom_fields_select\"\n\ttestName := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field_choice_set\" \"test\" {\n  name = \"%[1]s\"\n  extra_choices = [\n    [\"red\", \"red\"],\n    [\"blue\", \"blue\"]\n  ]\n}\n\nresource \"netbox_custom_field\" \"test\" {\n  name = \"%[1]s\"\n  type = \"select\"\n  content_types = [\"virtualization.vminterface\"]\n  weight = 101\n  default = \"red\"\n  choice_set_id = netbox_custom_field_choice_set.test.id\n  description = \"select field\"\n  label = \"external\"\n  required = false\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"type\", \"select\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"default\", \"red\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttr(\"netbox_custom_field.test\", \"content_types.*\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_custom_field.test\", \"choice_set_id\", \"netbox_custom_field_choice_set.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"weight\", \"101\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"default\", \"red\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"description\", \"select field\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"label\", \"external\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"required\", \"false\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field_choice_set\" \"test\" {\n  name = \"%[1]s\"\n  extra_choices = [\n    [\"red\", \"red\"],\n    [\"blue\", \"blue\"]\n  ]\n}\n\nresource \"netbox_custom_field\" \"test\" {\n  name = \"%[1]s\"\n  type = \"select\"\n  content_types = [\"virtualization.vminterface\"]\n  weight = 102\n  default = \"red\"\n  choice_set_id = netbox_custom_field_choice_set.test.id\n  description = \"select field\"\n  label = \"external\"\n  required = true\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"type\", \"select\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"default\", \"red\"),\n\t\t\t\t\tresource.TestCheckTypeSetElemAttr(\"netbox_custom_field.test\", \"content_types.*\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_custom_field.test\", \"choice_set_id\", \"netbox_custom_field_choice_set.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"weight\", \"102\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"default\", \"red\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"description\", \"select field\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"label\", \"external\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"required\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field_choice_set\" \"test\" {\n  name = \"%[1]s\"\n  extra_choices = [\n    [\"red\", \"red\"],\n    [\"blue\", \"blue\"]\n  ]\n}\n\nresource \"netbox_custom_field\" \"test\" {\n  name = \"%[1]s\"\n  type = \"select\"\n  content_types = [\"virtualization.vminterface\"]\n  weight = 102\n  default = \"red\"\n  choice_set_id = netbox_custom_field_choice_set.test.id\n  description = \"select field\"\n  label = \"external\"\n  required = false\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_custom_field.test\", \"required\", \"false\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxDeviceStatusOptions = []string{\"offline\", \"active\", \"planned\", \"staged\", \"failed\", \"inventory\", \"decommissioning\"}\nvar resourceNetboxDeviceRackFaceOptions = []string{\"front\", \"rear\"}\n\nfunc resourceNetboxDevice() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxDeviceCreate,\n\t\tReadContext:   resourceNetboxDeviceRead,\n\t\tUpdateContext: resourceNetboxDeviceUpdate,\n\t\tDeleteContext: resourceNetboxDeviceDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#devices):\n\n> Every piece of hardware which is installed within a site or rack exists in NetBox as a device. Devices are measured in rack units (U) and can be half depth or full depth. A device may have a height of 0U: These devices do not consume vertical rack space and cannot be assigned to a particular rack unit. A common example of a 0U device is a vertically-mounted PDU.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"device_type_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"cluster_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"platform_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"serial\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"config_template_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"asset_tag\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"primary_ipv4\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"primary_ipv6\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxDeviceStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxDeviceStatusOptions),\n\t\t\t\tDefault:      \"active\",\n\t\t\t},\n\t\t\t\"rack_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"rack_face\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"rack_position\"},\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxDeviceRackFaceOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxDeviceRackFaceOptions),\n\t\t\t},\n\t\t\t\"rack_position\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"virtual_chassis_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"virtual_chassis_master\", \"virtual_chassis_id\"},\n\t\t\t},\n\t\t\t\"virtual_chassis_position\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"virtual_chassis_priority\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"virtual_chassis_master\": {\n\t\t\t\tType:         schema.TypeBool,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"virtual_chassis_master\", \"virtual_chassis_id\"},\n\t\t\t},\n\t\t\t\"local_context_data\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"This is best managed through the use of `jsonencode` and a map of settings.\",\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tdata := models.WritableDeviceWithConfigContext{\n\t\tName: &name,\n\t}\n\n\ttypeIDValue, ok := d.GetOk(\"device_type_id\")\n\tif ok {\n\t\ttypeID := int64(typeIDValue.(int))\n\t\tdata.DeviceType = &typeID\n\t}\n\n\tif assetTagValue, ok := d.GetOk(\"asset_tag\"); ok {\n\t\tassetTag := string(assetTagValue.(string))\n\t\tdata.AssetTag = &assetTag\n\t}\n\n\tdata.Comments = d.Get(\"comments\").(string)\n\n\tdata.Description = d.Get(\"description\").(string)\n\n\tdata.Serial = d.Get(\"serial\").(string)\n\n\tdata.Status = d.Get(\"status\").(string)\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\ttenantID := int64(tenantIDValue.(int))\n\t\tdata.Tenant = &tenantID\n\t}\n\n\tplatformIDValue, ok := d.GetOk(\"platform_id\")\n\tif ok {\n\t\tplatformID := int64(platformIDValue.(int))\n\t\tdata.Platform = &platformID\n\t}\n\n\tlocationIDValue, ok := d.GetOk(\"location_id\")\n\tif ok {\n\t\tlocationID := int64(locationIDValue.(int))\n\t\tdata.Location = &locationID\n\t}\n\n\tclusterIDValue, ok := d.GetOk(\"cluster_id\")\n\tif ok {\n\t\tclusterID := int64(clusterIDValue.(int))\n\t\tdata.Cluster = &clusterID\n\t}\n\n\troleIDValue, ok := d.GetOk(\"role_id\")\n\tif ok {\n\t\troleID := int64(roleIDValue.(int))\n\t\tdata.Role = &roleID\n\t}\n\n\tsiteIDValue, ok := d.GetOk(\"site_id\")\n\tif ok {\n\t\tsiteID := int64(siteIDValue.(int))\n\t\tdata.Site = &siteID\n\t}\n\n\tconfigTemplateIDValue, ok := d.GetOk(\"config_template_id\")\n\tif ok {\n\t\tconfigTemplateID := int64(configTemplateIDValue.(int))\n\t\tdata.ConfigTemplate = &configTemplateID\n\t}\n\n\tdata.Rack = getOptionalInt(d, \"rack_id\")\n\tdata.Face = getOptionalStr(d, \"rack_face\", false)\n\n\trackPosition, ok := d.GetOk(\"rack_position\")\n\tif ok && rackPosition.(float64) > 0 {\n\t\tdata.Position = float64ToPtr(rackPosition.(float64))\n\t} else {\n\t\tdata.Position = nil\n\t}\n\n\tdata.VirtualChassis = getOptionalInt(d, \"virtual_chassis_id\")\n\tdata.VcPosition = getOptionalInt(d, \"virtual_chassis_position\")\n\tdata.VcPriority = getOptionalInt(d, \"virtual_chassis_priority\")\n\n\tlocalContextValue, ok := d.GetOk(\"local_context_data\")\n\tif ok {\n\t\tvar jsonObj any\n\t\tlocalContextBA := []byte(localContextValue.(string))\n\t\tif err := json.Unmarshal(localContextBA, &jsonObj); err == nil {\n\t\t\tdata.LocalContextData = jsonObj\n\t\t}\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tparams := dcim.NewDcimDevicesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimDevicesCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\tif vcMaster, ok := d.GetOk(\"virtual_chassis_master\"); ok {\n\t\tvar err error\n\t\tif vcMaster.(bool) {\n\t\t\terr = virtualChassisUpdateMaster(api, *data.VirtualChassis, &(res.GetPayload().ID))\n\t\t} else {\n\t\t\terr = virtualChassisUpdateMaster(api, *data.VirtualChassis, nil)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn diag.FromErr(err)\n\t\t}\n\t}\n\n\treturn resourceNetboxDeviceRead(ctx, d, m)\n}\n\nfunc resourceNetboxDeviceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := dcim.NewDcimDevicesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimDevicesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDevicesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\tdevice := res.GetPayload()\n\n\td.Set(\"name\", device.Name)\n\n\tif device.DeviceType != nil {\n\t\td.Set(\"device_type_id\", device.DeviceType.ID)\n\t}\n\n\tif device.PrimaryIp4 != nil {\n\t\td.Set(\"primary_ipv4\", device.PrimaryIp4.ID)\n\t} else {\n\t\td.Set(\"primary_ipv4\", nil)\n\t}\n\n\tif device.PrimaryIp6 != nil {\n\t\td.Set(\"primary_ipv6\", device.PrimaryIp6.ID)\n\t} else {\n\t\td.Set(\"primary_ipv6\", nil)\n\t}\n\n\tif device.Tenant != nil {\n\t\td.Set(\"tenant_id\", device.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tif device.Platform != nil {\n\t\td.Set(\"platform_id\", device.Platform.ID)\n\t} else {\n\t\td.Set(\"platform_id\", nil)\n\t}\n\n\tif device.Location != nil {\n\t\td.Set(\"location_id\", device.Location.ID)\n\t} else {\n\t\td.Set(\"location_id\", nil)\n\t}\n\n\tif device.Cluster != nil {\n\t\td.Set(\"cluster_id\", device.Cluster.ID)\n\t} else {\n\t\td.Set(\"cluster_id\", nil)\n\t}\n\n\tif device.Role != nil {\n\t\td.Set(\"role_id\", device.Role.ID)\n\t} else {\n\t\td.Set(\"role_id\", nil)\n\t}\n\n\tif device.Site != nil {\n\t\td.Set(\"site_id\", device.Site.ID)\n\t} else {\n\t\td.Set(\"site_id\", nil)\n\t}\n\n\tif device.ConfigTemplate != nil {\n\t\td.Set(\"config_template_id\", device.ConfigTemplate.ID)\n\t} else {\n\t\td.Set(\"config_template_id\", nil)\n\t}\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\td.Set(\"asset_tag\", device.AssetTag)\n\n\td.Set(\"comments\", device.Comments)\n\n\td.Set(\"description\", device.Description)\n\n\td.Set(\"serial\", device.Serial)\n\n\td.Set(\"status\", device.Status.Value)\n\n\tif device.Rack != nil {\n\t\td.Set(\"rack_id\", device.Rack.ID)\n\t} else {\n\t\td.Set(\"rack_id\", nil)\n\t}\n\n\tif device.Face != nil {\n\t\td.Set(\"rack_face\", device.Face.Value)\n\t} else {\n\t\td.Set(\"rack_face\", nil)\n\t}\n\n\td.Set(\"rack_position\", device.Position)\n\n\tif device.VirtualChassis != nil {\n\t\td.Set(\"virtual_chassis_id\", device.VirtualChassis.ID)\n\t\td.Set(\n\t\t\t\"virtual_chassis_master\",\n\t\t\tdevice.VirtualChassis.Master != nil && device.VirtualChassis.Master.ID == device.ID,\n\t\t)\n\t} else {\n\t\td.Set(\"virtual_chassis_id\", 0)\n\t\td.Set(\"virtual_chassis_master\", false)\n\t}\n\td.Set(\"virtual_chassis_position\", device.VcPosition)\n\td.Set(\"virtual_chassis_priority\", device.VcPriority)\n\n\tif device.LocalContextData != nil {\n\t\tif jsonArr, err := json.Marshal(device.LocalContextData); err == nil {\n\t\t\td.Set(\"local_context_data\", string(jsonArr))\n\t\t}\n\t} else {\n\t\td.Set(\"local_context_data\", nil)\n\t}\n\n\tapi.readTags(d, device.Tags)\n\treturn diags\n}\n\nfunc resourceNetboxDeviceUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableDeviceWithConfigContext{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tstatus := d.Get(\"status\").(string)\n\tdata.Status = status\n\n\ttypeIDValue, ok := d.GetOk(\"device_type_id\")\n\tif ok {\n\t\ttypeID := int64(typeIDValue.(int))\n\t\tdata.DeviceType = &typeID\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\ttenantID := int64(tenantIDValue.(int))\n\t\tdata.Tenant = &tenantID\n\t}\n\n\tplatformIDValue, ok := d.GetOk(\"platform_id\")\n\tif ok {\n\t\tplatformID := int64(platformIDValue.(int))\n\t\tdata.Platform = &platformID\n\t}\n\n\tlocationIDValue, ok := d.GetOk(\"location_id\")\n\tif ok {\n\t\tlocationID := int64(locationIDValue.(int))\n\t\tdata.Location = &locationID\n\t}\n\n\tclusterIDValue, ok := d.GetOk(\"cluster_id\")\n\tif ok {\n\t\tclusterID := int64(clusterIDValue.(int))\n\t\tdata.Cluster = &clusterID\n\t}\n\n\troleIDValue, ok := d.GetOk(\"role_id\")\n\tif ok {\n\t\troleID := int64(roleIDValue.(int))\n\t\tdata.Role = &roleID\n\t}\n\n\tsiteIDValue, ok := d.GetOk(\"site_id\")\n\tif ok {\n\t\tsiteID := int64(siteIDValue.(int))\n\t\tdata.Site = &siteID\n\t}\n\n\tconfigTemplateIDValue, ok := d.GetOk(\"config_template_id\")\n\tif ok {\n\t\tconfigTemplateID := int64(configTemplateIDValue.(int))\n\t\tdata.ConfigTemplate = &configTemplateID\n\t}\n\n\tdata.Rack = getOptionalInt(d, \"rack_id\")\n\tdata.Face = getOptionalStr(d, \"rack_face\", false)\n\tdata.Position = getOptionalFloat(d, \"rack_position\")\n\n\tdata.VirtualChassis = getOptionalInt(d, \"virtual_chassis_id\")\n\tdata.VcPosition = getOptionalInt(d, \"virtual_chassis_position\")\n\tdata.VcPriority = getOptionalInt(d, \"virtual_chassis_priority\")\n\n\tlocalContextValue, ok := d.GetOk(\"local_context_data\")\n\tif ok {\n\t\tvar jsonObj any\n\t\tlocalContextBA := []byte(localContextValue.(string))\n\t\tif err := json.Unmarshal(localContextBA, &jsonObj); err == nil {\n\t\t\tdata.LocalContextData = jsonObj\n\t\t}\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tif d.HasChanges(\"asset_tag\") {\n\t\tif assetTagValue, ok := d.GetOk(\"asset_tag\"); ok {\n\t\t\tassetTag := assetTagValue.(string)\n\t\t\tdata.AssetTag = &assetTag\n\t\t} else {\n\t\t\tassetTag := \" \"\n\t\t\tdata.AssetTag = &assetTag\n\t\t}\n\t}\n\n\tif d.HasChanges(\"comments\") {\n\t\t// check if comment is set\n\t\tif commentsValue, ok := d.GetOk(\"comments\"); ok {\n\t\t\tdata.Comments = commentsValue.(string)\n\t\t} else {\n\t\t\tdata.Comments = \" \"\n\t\t}\n\t}\n\tif d.HasChanges(\"description\") {\n\t\t// check if description is set\n\t\tif descriptionValue, ok := d.GetOk(\"description\"); ok {\n\t\t\tdata.Description = descriptionValue.(string)\n\t\t} else {\n\t\t\tdata.Description = \" \"\n\t\t}\n\t}\n\n\tif d.HasChanges(\"serial\") {\n\t\t// check if serial is set\n\t\tserialValue, ok := d.GetOk(\"serial\")\n\t\tserial := \"\"\n\t\tif !ok {\n\t\t\t// Setting an space string deletes the serial\n\t\t\tserial = \" \"\n\t\t} else {\n\t\t\tserial = serialValue.(string)\n\t\t}\n\t\tdata.Serial = serial\n\t}\n\n\tparams := dcim.NewDcimDevicesUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimDevicesUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tif d.HasChange(\"virtual_chassis_master\") && data.VirtualChassis != nil {\n\t\tvar err error\n\t\tif vcMaster, ok := d.GetOk(\"virtual_chassis_master\"); ok {\n\t\t\tif vcMaster.(bool) {\n\t\t\t\terr = virtualChassisUpdateMaster(api, *data.VirtualChassis, &id)\n\t\t\t} else {\n\t\t\t\terr = virtualChassisUpdateMaster(api, *data.VirtualChassis, nil)\n\t\t\t}\n\t\t} else {\n\t\t\t// It was set before, but no longer set, remove it as master\n\t\t\terr = virtualChassisUpdateMaster(api, *data.VirtualChassis, nil)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn diag.FromErr(err)\n\t\t}\n\t}\n\n\treturn resourceNetboxDeviceRead(ctx, d, m)\n}\n\nfunc resourceNetboxDeviceDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\t// If the device is member of a virtual chassis and it's the master, we cannot\n\t// delete it directly. We first need to update it to not be the master.\n\tif virtualChassisIDValue, ok := d.GetOk(\"virtual_chassis_id\"); ok {\n\t\tif d.Get(\"virtual_chassis_master\").(bool) {\n\t\t\tvirtualChassisID := int64(virtualChassisIDValue.(int))\n\t\t\terr := virtualChassisUpdateMaster(api, virtualChassisID, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn diag.FromErr(err)\n\t\t\t}\n\t\t}\n\t}\n\n\tparams := dcim.NewDcimDevicesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimDevicesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDevicesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\treturn diags\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_bay.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxDeviceBay() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDeviceBayCreate,\n\t\tRead:   resourceNetboxDeviceBayRead,\n\t\tUpdate: resourceNetboxDeviceBayUpdate,\n\t\tDelete: resourceNetboxDeviceBayDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/devicebay/):\n\n> Device bays represent a space or slot within a device in which a field-replaceable device may be installed. A common example is that of a chassis-based server that holds a number of blades which may contain device components that don't fit the module pattern. Devices in turn hold additional components that become available to the parent device.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"installed_device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceBayCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableDeviceBay{\n\t\tDevice:          int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:            strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:           getOptionalStr(d, \"label\", false),\n\t\tInstalledDevice: getOptionalInt(d, \"installed_device_id\"),\n\t\tDescription:     getOptionalStr(d, \"description\", false),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimDeviceBaysCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimDeviceBaysCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDeviceBayRead(d, m)\n}\n\nfunc resourceNetboxDeviceBayRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimDeviceBaysReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimDeviceBaysRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDeviceBaysReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tdeviceBay := res.GetPayload()\n\n\tif deviceBay.Device != nil {\n\t\td.Set(\"device_id\", deviceBay.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", deviceBay.Name)\n\td.Set(\"label\", deviceBay.Label)\n\tif deviceBay.InstalledDevice != nil {\n\t\td.Set(\"installed_device_id\", deviceBay.InstalledDevice.ID)\n\t}\n\td.Set(\"description\", deviceBay.Description)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDeviceBayUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableDeviceBay{\n\t\tDevice:          int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:            strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:           getOptionalStr(d, \"label\", true),\n\t\tInstalledDevice: getOptionalInt(d, \"installed_device_id\"),\n\t\tDescription:     getOptionalStr(d, \"description\", true),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimDeviceBaysPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimDeviceBaysPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDeviceBayRead(d, m)\n}\n\nfunc resourceNetboxDeviceBayDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimDeviceBaysDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimDeviceBaysDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_bay_template.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxDeviceBayTemplate() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxDeviceBayTemplateCreate,\n\t\tReadContext:   resourceNetboxDeviceBayTemplateRead,\n\t\tUpdateContext: resourceNetboxDeviceBayTemplateUpdate,\n\t\tDeleteContext: resourceNetboxDeviceBayTemplateDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/devicebaytemplate/):\n\n> A template for a device bay that will be created on all instantiations of the parent device type.`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_type_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 64),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceBayTemplateCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tlabel := d.Get(\"label\").(string)\n\n\tdata := models.WritableDeviceBayTemplate{\n\t\tName:        &name,\n\t\tDescription: description,\n\t\tLabel:       label,\n\t}\n\n\tif deviceTypeID, ok := d.Get(\"device_type_id\").(int); ok && deviceTypeID != 0 {\n\t\tdata.DeviceType = int64ToPtr(int64(deviceTypeID))\n\t}\n\tparams := dcim.NewDcimDeviceBayTemplatesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimDeviceBayTemplatesCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn diags\n}\n\nfunc resourceNetboxDeviceBayTemplateRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tvar diags diag.Diagnostics\n\n\tparams := dcim.NewDcimDeviceBayTemplatesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimDeviceBayTemplatesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDeviceBayTemplatesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\ttmpl := res.GetPayload()\n\n\td.Set(\"device_type_id\", tmpl.DeviceType.ID)\n\td.Set(\"name\", tmpl.Name)\n\td.Set(\"description\", tmpl.Description)\n\td.Set(\"label\", tmpl.Label)\n\n\treturn diags\n}\n\nfunc resourceNetboxDeviceBayTemplateUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tlabel := d.Get(\"label\").(string)\n\n\tdata := models.WritableDeviceBayTemplate{\n\t\tName:        &name,\n\t\tDescription: description,\n\t\tLabel:       label,\n\t}\n\n\tif d.HasChange(\"device_type_id\") {\n\t\tdeviceTypeID := int64(d.Get(\"device_type_id\").(int))\n\t\tdata.DeviceType = &deviceTypeID\n\t}\n\n\tparams := dcim.NewDcimDeviceBayTemplatesPartialUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Dcim.DcimDeviceBayTemplatesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxDeviceBayTemplateDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimDeviceBayTemplatesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimDeviceBayTemplatesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDeviceBayTemplatesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_bay_template_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc TestAccNetboxDeviceBayTemplate_basic(t *testing.T) {\n\ttestSlug := \"device_bay_template\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n\tname = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n\tmodel = \"%[1]s\"\n\tslug = \"%[2]s\"\n\tpart_number = \"%[2]s\"\n\tmanufacturer_id = netbox_manufacturer.test.id\n\tsubdevice_role = \"parent\"\n}\n\nresource \"netbox_device_bay_template\" \"test\" {\n\tname = \"%[1]s\"\n\tdevice_type_id = netbox_device_type.test.id\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay_template.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_bay_template.test\", \"device_type_id\", \"netbox_device_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_bay_template.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDeviceBayTemplate_opts(t *testing.T) {\n\ttestSlug := \"device_bay_template\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n\tname = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n\tmodel = \"%[1]s\"\n\tslug = \"%[2]s\"\n\tpart_number = \"%[2]s\"\n\tsubdevice_role = \"parent\"\n\tmanufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_bay_template\" \"test\" {\n\tname = \"%[1]s\"\n\tdescription = \"%[1]s description\"\n\tlabel = \"%[1]s label\"\n\tdevice_type_id = netbox_device_type.test.id\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay_template.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay_template.test\", \"description\", fmt.Sprintf(\"%s description\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay_template.test\", \"label\", fmt.Sprintf(\"%s label\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_bay_template.test\", \"device_type_id\", \"netbox_device_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n\tname = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n\tmodel = \"%[1]s\"\n\tslug = \"%[2]s\"\n\tpart_number = \"%[2]s\"\n\tsubdevice_role = \"parent\"\n\tmanufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_bay_template\" \"test\" {\n\tname = \"%[1]s\"\n\tdescription = \"%[1]s description\"\n\tlabel = \"%[1]s label\"\n\tdevice_type_id = netbox_device_type.test.id\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay_template.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay_template.test\", \"description\", fmt.Sprintf(\"%s description\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay_template.test\", \"label\", fmt.Sprintf(\"%s label\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_bay_template.test\", \"device_type_id\", \"netbox_device_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_bay_template\", &resource.Sweeper{\n\t\tName:         \"netbox_device_bay_template\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimDeviceBayTemplatesListParams()\n\t\t\tres, err := api.Dcim.DcimDeviceBayTemplatesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tmpl := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*tmpl.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimDeviceBayTemplatesDeleteParams().WithID(tmpl.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimDeviceBayTemplatesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device bay template\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_bay_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDeviceBayFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n  subdevice_role = \"parent\"\n}\n\nresource \"netbox_device_type\" \"test_installed\" {\n  model = \"%[1]s_installed\"\n  manufacturer_id = netbox_manufacturer.test.id\n  u_height = 0\n  subdevice_role = \"child\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device\" \"test_installed\" {\n  name = \"%[1]s_installed\"\n  device_type_id = netbox_device_type.test_installed.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n`, testName)\n}\n\nfunc TestAccNetboxDeviceBay_basic(t *testing.T) {\n\ttestSlug := \"device_bay_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDeviceBayDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceBayFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  label = \"%[1]s_label\"\n  description = \"%[1]s_description\"\n  installed_device_id = netbox_device.test_installed.id\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_bay.test\", \"installed_device_id\", \"netbox_device.test_installed\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_bay.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceBayFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  installed_device_id = netbox_device.test_installed.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"label\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_bay.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_bay.test\", \"installed_device_id\", \"netbox_device.test_installed\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_bay.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_bay.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDeviceBayDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each module bay\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_bay\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimDeviceBaysReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimDeviceBaysRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_bay (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimDeviceBaysReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_bay\", &resource.Sweeper{\n\t\tName:         \"netbox_device_bay\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimDeviceBaysListParams()\n\t\t\tres, err := api.Dcim.DcimDeviceBaysList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, deviceBay := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*deviceBay.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimDeviceBaysDeleteParams().WithID(deviceBay.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimDeviceBaysDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_bay\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_console_port.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxDeviceConsolePort() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDeviceConsolePortCreate,\n\t\tRead:   resourceNetboxDeviceConsolePortRead,\n\t\tUpdate: resourceNetboxDeviceConsolePortUpdate,\n\t\tDelete: resourceNetboxDeviceConsolePortDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/consoleport/):\n\n> A console port provides connectivity to the physical console of a device. These are typically used for temporary access by someone who is physically near the device, or for remote out-of-band access provided via a networked console server.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"module_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"One of [de-9, db-25, rj-11, rj-12, rj-45, mini-din-8, usb-a, usb-b, usb-c, usb-mini-a, usb-mini-b, usb-micro-a, usb-micro-b, usb-micro-ab, other]\",\n\t\t\t},\n\t\t\t\"speed\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"One of [1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]\",\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_connected\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tDefault:  false,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceConsolePortCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableConsolePort{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:         getOptionalStr(d, \"label\", false),\n\t\tType:          getOptionalStr(d, \"type\", false),\n\t\tSpeed:         getOptionalInt(d, \"speed\"),\n\t\tDescription:   getOptionalStr(d, \"description\", false),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimConsolePortsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimConsolePortsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDeviceConsolePortRead(d, m)\n}\n\nfunc resourceNetboxDeviceConsolePortRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimConsolePortsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimConsolePortsRead(params, nil)\n\n\tif err != nil {\n\t\tif errIntf, ok := err.(*dcim.DcimConsolePortsReadDefault); ok && errIntf.Code() == 404 {\n\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\td.SetId(\"\")\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\tconsolePort := res.GetPayload()\n\n\tif consolePort.Device != nil {\n\t\td.Set(\"device_id\", consolePort.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", consolePort.Name)\n\n\tif consolePort.Module != nil {\n\t\td.Set(\"module_id\", consolePort.Module.ID)\n\t} else {\n\t\td.Set(\"module_id\", nil)\n\t}\n\n\td.Set(\"label\", consolePort.Label)\n\n\tif consolePort.Type != nil {\n\t\td.Set(\"type\", consolePort.Type.Value)\n\t} else {\n\t\td.Set(\"type\", nil)\n\t}\n\n\tif consolePort.Speed != nil {\n\t\td.Set(\"speed\", consolePort.Speed.Value)\n\t} else {\n\t\td.Set(\"speed\", nil)\n\t}\n\n\td.Set(\"description\", consolePort.Description)\n\td.Set(\"mark_connected\", consolePort.MarkConnected)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDeviceConsolePortUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableConsolePort{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:         getOptionalStr(d, \"label\", true),\n\t\tType:          getOptionalStr(d, \"type\", false),\n\t\tSpeed:         getOptionalInt(d, \"speed\"),\n\t\tDescription:   getOptionalStr(d, \"description\", true),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimConsolePortsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimConsolePortsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDeviceConsolePortRead(d, m)\n}\n\nfunc resourceNetboxDeviceConsolePortDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimConsolePortsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimConsolePortsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_console_port_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDeviceConsolePortFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id = netbox_device.test.id\n  module_bay_id = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status = \"active\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxDeviceConsolePort_basic(t *testing.T) {\n\ttestSlug := \"device_console_port_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDeviceConsolePortDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceConsolePortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_console_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n\n\tmodule_id = netbox_module.test.id\n\tlabel = \"%[1]s_label\"\n\ttype = \"de-9\"\n\tspeed = 1200\n  mark_connected = true\n\tdescription = \"%[1]s_description\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"type\", \"de-9\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"speed\", \"1200\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"mark_connected\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_console_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_console_port.test\", \"module_id\", \"netbox_module.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceConsolePortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_console_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"label\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"type\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"speed\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"mark_connected\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_port.test\", \"module_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_console_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_console_port.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDeviceConsolePortDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each console port\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_console_port\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimConsolePortsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimConsolePortsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_console_port (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimConsolePortsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_console_port\", &resource.Sweeper{\n\t\tName:         \"netbox_device_console_port\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimConsolePortsListParams()\n\t\t\tres, err := api.Dcim.DcimConsolePortsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, consolePort := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*consolePort.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimConsolePortsDeleteParams().WithID(consolePort.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimConsolePortsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_console_port\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_console_server_port.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxDeviceConsoleServerPort() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDeviceConsoleServerPortCreate,\n\t\tRead:   resourceNetboxDeviceConsoleServerPortRead,\n\t\tUpdate: resourceNetboxDeviceConsoleServerPortUpdate,\n\t\tDelete: resourceNetboxDeviceConsoleServerPortDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/consoleserverport/):\n\n> A console server is a device which provides remote access to the local consoles of connected devices. They are typically used to provide remote out-of-band access to network devices, and generally connect to console ports.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"module_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"One of [de-9, db-25, rj-11, rj-12, rj-45, mini-din-8, usb-a, usb-b, usb-c, usb-mini-a, usb-mini-b, usb-micro-a, usb-micro-b, usb-micro-ab, other]\",\n\t\t\t},\n\t\t\t\"speed\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"One of [1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]\",\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_connected\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tDefault:  false,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceConsoleServerPortCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableConsoleServerPort{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:         getOptionalStr(d, \"label\", true),\n\t\tType:          getOptionalStr(d, \"type\", false),\n\t\tSpeed:         getOptionalInt(d, \"speed\"),\n\t\tDescription:   getOptionalStr(d, \"description\", false),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimConsoleServerPortsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimConsoleServerPortsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDeviceConsoleServerPortRead(d, m)\n}\n\nfunc resourceNetboxDeviceConsoleServerPortRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimConsoleServerPortsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimConsoleServerPortsRead(params, nil)\n\n\tif err != nil {\n\t\tif errIntf, ok := err.(*dcim.DcimConsoleServerPortsReadDefault); ok && errIntf.Code() == 404 {\n\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\td.SetId(\"\")\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\tconsoleServerPort := res.GetPayload()\n\n\tif consoleServerPort.Device != nil {\n\t\td.Set(\"device_id\", consoleServerPort.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", consoleServerPort.Name)\n\n\tif consoleServerPort.Module != nil {\n\t\td.Set(\"module_id\", consoleServerPort.Module.ID)\n\t} else {\n\t\td.Set(\"module_id\", nil)\n\t}\n\n\td.Set(\"label\", consoleServerPort.Label)\n\n\tif consoleServerPort.Type != nil {\n\t\td.Set(\"type\", consoleServerPort.Type.Value)\n\t} else {\n\t\td.Set(\"type\", nil)\n\t}\n\n\tif consoleServerPort.Speed != nil {\n\t\td.Set(\"speed\", consoleServerPort.Speed.Value)\n\t} else {\n\t\td.Set(\"speed\", nil)\n\t}\n\n\td.Set(\"description\", consoleServerPort.Description)\n\td.Set(\"mark_connected\", consoleServerPort.MarkConnected)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDeviceConsoleServerPortUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableConsoleServerPort{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:         getOptionalStr(d, \"label\", true),\n\t\tType:          getOptionalStr(d, \"type\", false),\n\t\tSpeed:         getOptionalInt(d, \"speed\"),\n\t\tDescription:   getOptionalStr(d, \"description\", true),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimConsoleServerPortsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimConsoleServerPortsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDeviceConsoleServerPortRead(d, m)\n}\n\nfunc resourceNetboxDeviceConsoleServerPortDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimConsoleServerPortsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimConsoleServerPortsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_console_server_port_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDeviceConsoleServerPortFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id = netbox_device.test.id\n  module_bay_id = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status = \"active\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxDeviceConsoleServerPort_basic(t *testing.T) {\n\ttestSlug := \"device_console_server_port_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDeviceConsoleServerPortDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceConsoleServerPortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_console_server_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n\n\tmodule_id = netbox_module.test.id\n\tlabel = \"%[1]s_label\"\n\ttype = \"de-9\"\n\tspeed = 1200\n  mark_connected = true\n\tdescription = \"%[1]s_description\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"type\", \"de-9\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"speed\", \"1200\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"mark_connected\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_console_server_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_console_server_port.test\", \"module_id\", \"netbox_module.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceConsoleServerPortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_console_server_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"label\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"type\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"speed\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"mark_connected\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_console_server_port.test\", \"module_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_console_server_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_console_server_port.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDeviceConsoleServerPortDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each console server port\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_console_server_port\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimConsoleServerPortsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimConsoleServerPortsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_console_server_port (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimConsoleServerPortsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_console_server_port\", &resource.Sweeper{\n\t\tName:         \"netbox_device_console_server_port\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimConsoleServerPortsListParams()\n\t\t\tres, err := api.Dcim.DcimConsoleServerPortsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, csPort := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*csPort.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimConsoleServerPortsDeleteParams().WithID(csPort.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimConsoleServerPortsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_console_server_port\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_front_port.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxDeviceFrontPort() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDeviceFrontPortCreate,\n\t\tRead:   resourceNetboxDeviceFrontPortRead,\n\t\tUpdate: resourceNetboxDeviceFrontPortUpdate,\n\t\tDelete: resourceNetboxDeviceFrontPortDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/frontport/):\n\n> Front ports are pass-through ports which represent physical cable connections that comprise part of a longer path. For example, the ports on the front face of a UTP patch panel would be modeled in NetBox as front ports. Each port is assigned a physical type, and must be mapped to a specific rear port on the same device. A single rear port may be mapped to multiple front ports, using numeric positions to annotate the specific alignment of each.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: \"One of [8p8c, 8p6c, 8p4c, 8p2c, 6p6c, 6p4c, 6p2c, 4p4c, 4p2c, gg45, tera-4p, tera-2p, tera-1p, 110-punch, bnc, f, n, mrj21, fc, lc, lc-pc, lc-upc, lc-apc, lsh, lsh-pc, lsh-upc, lsh-apc, mpo, mtrj, sc, sc-pc, sc-upc, sc-apc, st, cs, sn, sma-905, sma-906, urm-p2, urm-p4, urm-p8, splice, other]\",\n\t\t\t},\n\t\t\t\"rear_port_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"rear_port_position\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"module_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_connected\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tDefault:  false,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceFrontPortCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableFrontPort{\n\t\tDevice:           int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:             strToPtr(d.Get(\"name\").(string)),\n\t\tType:             strToPtr(d.Get(\"type\").(string)),\n\t\tRearPort:         int64ToPtr(int64(d.Get(\"rear_port_id\").(int))),\n\t\tRearPortPosition: int64(d.Get(\"rear_port_position\").(int)),\n\t\tModule:           getOptionalInt(d, \"module_id\"),\n\t\tLabel:            getOptionalStr(d, \"label\", false),\n\t\tColor:            getOptionalStr(d, \"color_hex\", false),\n\t\tDescription:      getOptionalStr(d, \"description\", false),\n\t\tMarkConnected:    d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimFrontPortsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimFrontPortsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDeviceFrontPortRead(d, m)\n}\n\nfunc resourceNetboxDeviceFrontPortRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimFrontPortsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimFrontPortsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimFrontPortsReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tfrontPort := res.GetPayload()\n\n\tif frontPort.Device != nil {\n\t\td.Set(\"device_id\", frontPort.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", frontPort.Name)\n\n\tif frontPort.Type != nil {\n\t\td.Set(\"type\", frontPort.Type.Value)\n\t} else {\n\t\td.Set(\"type\", nil)\n\t}\n\n\tif frontPort.RearPort != nil {\n\t\td.Set(\"rear_port_id\", frontPort.RearPort.ID)\n\t} else {\n\t\td.Set(\"rear_port_id\", nil)\n\t}\n\n\td.Set(\"rear_port_position\", frontPort.RearPortPosition)\n\n\tif frontPort.Module != nil {\n\t\td.Set(\"module_id\", frontPort.Module.ID)\n\t} else {\n\t\td.Set(\"module_id\", nil)\n\t}\n\n\td.Set(\"label\", frontPort.Label)\n\td.Set(\"color_hex\", frontPort.Color)\n\td.Set(\"description\", frontPort.Description)\n\td.Set(\"mark_connected\", frontPort.MarkConnected)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDeviceFrontPortUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableFrontPort{\n\t\tDevice:           int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:             strToPtr(d.Get(\"name\").(string)),\n\t\tType:             strToPtr(d.Get(\"type\").(string)),\n\t\tRearPort:         int64ToPtr(int64(d.Get(\"rear_port_id\").(int))),\n\t\tRearPortPosition: int64(d.Get(\"rear_port_position\").(int)),\n\t\tModule:           getOptionalInt(d, \"module_id\"),\n\t\tLabel:            getOptionalStr(d, \"label\", true),\n\t\tColor:            getOptionalStr(d, \"color_hex\", false),\n\t\tDescription:      getOptionalStr(d, \"description\", true),\n\t\tMarkConnected:    d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimFrontPortsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimFrontPortsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDeviceFrontPortRead(d, m)\n}\n\nfunc resourceNetboxDeviceFrontPortDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimFrontPortsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimFrontPortsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_front_port_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDeviceFrontPortFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id = netbox_device.test.id\n  module_bay_id = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status = \"active\"\n}\n\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  type = \"8p8c\"\n  positions = 1\n  mark_connected = true\n}\n`, testName)\n}\n\nfunc TestAccNetboxDeviceFrontPort_basic(t *testing.T) {\n\ttestSlug := \"device_front_port_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDeviceFrontPortDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFrontPortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_front_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  type = \"8p8c\"\n  rear_port_id = netbox_device_rear_port.test.id\n  rear_port_position = 1\n\n  mark_connected = true\n  module_id = netbox_module.test.id\n  label = \"%[1]s_label\"\n  color_hex = \"123456\"\n  description = \"%[1]s_description\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"type\", \"8p8c\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"mark_connected\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"color_hex\", \"123456\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"rear_port_position\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_front_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_front_port.test\", \"rear_port_id\", \"netbox_device_rear_port.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_front_port.test\", \"module_id\", \"netbox_module.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFrontPortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_front_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  type = \"8p8c\"\n  rear_port_id = netbox_device_rear_port.test.id\n  rear_port_position = 1\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"type\", \"8p8c\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"mark_connected\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"label\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"color_hex\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"rear_port_position\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_front_port.test\", \"module_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_front_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_front_port.test\", \"rear_port_id\", \"netbox_device_rear_port.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_front_port.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDeviceFrontPortDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each front port\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_front_port\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimFrontPortsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimFrontPortsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_front_port (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimFrontPortsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_front_port\", &resource.Sweeper{\n\t\tName:         \"netbox_device_front_port\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimFrontPortsListParams()\n\t\t\tres, err := api.Dcim.DcimFrontPortsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, frontPort := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*frontPort.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimFrontPortsDeleteParams().WithID(frontPort.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimFrontPortsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_front_port\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_interface.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxDeviceInterfaceModeOptions = []string{\"access\", \"tagged\", \"tagged-all\", \"q-in-q\"}\n\nfunc resourceNetboxDeviceInterface() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxDeviceInterfaceCreate,\n\t\tReadContext:   resourceNetboxDeviceInterfaceRead,\n\t\tUpdateContext: resourceNetboxDeviceInterfaceUpdate,\n\t\tDeleteContext: resourceNetboxDeviceInterfaceDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/device/#interface):\n\n> Interfaces in NetBox represent network interfaces used to exchange data with connected devices. On modern networks, these are most commonly Ethernet, but other types are supported as well. IP addresses and VLANs can be assigned to interfaces.`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"enabled\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  true,\n\t\t\t},\n\t\t\t\"lag_device_interface_id\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"If this device is a member of a LAG group, you can reference the LAG interface here.\",\n\t\t\t},\n\t\t\t\"mac_address\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tComputed:    true,\n\t\t\t\tDescription: \"The MAC address as string from the first MAC address assigned to this interface, if any.\",\n\t\t\t},\n\t\t\t\"mac_addresses\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"mac_address\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"mgmtonly\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mode\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxDeviceInterfaceModeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxDeviceInterfaceModeOptions),\n\t\t\t},\n\t\t\t\"mtu\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.IntBetween(1, 65536),\n\t\t\t},\n\t\t\t\"parent_device_interface_id\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"The netbox_device_interface id of the parent interface. Useful if this interface is a logical interface.\",\n\t\t\t},\n\t\t\t\"speed\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"tagged_vlans\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"untagged_vlan\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceInterfaceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tlabel := d.Get(\"label\").(string)\n\tinterfaceType := d.Get(\"type\").(string)\n\tenabled := d.Get(\"enabled\").(bool)\n\tmgmtonly := d.Get(\"mgmtonly\").(bool)\n\tmode := d.Get(\"mode\").(string)\n\ttags, err := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\ttaggedVlans := toInt64List(d.Get(\"tagged_vlans\"))\n\tdeviceID := int64(d.Get(\"device_id\").(int))\n\n\tdata := models.WritableInterface{\n\t\tName:         &name,\n\t\tDescription:  description,\n\t\tLabel:        label,\n\t\tType:         &interfaceType,\n\t\tEnabled:      enabled,\n\t\tMgmtOnly:     mgmtonly,\n\t\tMode:         mode,\n\t\tTags:         tags,\n\t\tTaggedVlans:  taggedVlans,\n\t\tDevice:       &deviceID,\n\t\tWirelessLans: []int64{},\n\t\tVdcs:         []int64{},\n\t}\n\tif lag, ok := d.Get(\"lag_device_interface_id\").(int); ok && lag != 0 {\n\t\tdata.Lag = int64ToPtr(int64(lag))\n\t}\n\tif mtu, ok := d.Get(\"mtu\").(int); ok && mtu != 0 {\n\t\tdata.Mtu = int64ToPtr(int64(mtu))\n\t}\n\tif parent, ok := d.Get(\"parent_device_interface_id\").(int); ok && parent != 0 {\n\t\tdata.Parent = int64ToPtr(int64(parent))\n\t}\n\tif speed, ok := d.Get(\"speed\").(int); ok && speed != 0 {\n\t\tdata.Speed = int64ToPtr(int64(speed))\n\t}\n\tif untaggedVlan, ok := d.Get(\"untagged_vlan\").(int); ok && untaggedVlan != 0 {\n\t\tdata.UntaggedVlan = int64ToPtr(int64(untaggedVlan))\n\t}\n\n\tparams := dcim.NewDcimInterfacesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimInterfacesCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn diags\n}\n\nfunc resourceNetboxDeviceInterfaceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tvar diags diag.Diagnostics\n\n\tparams := dcim.NewDcimInterfacesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimInterfacesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimInterfacesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\tiface := res.GetPayload()\n\n\td.Set(\"name\", iface.Name)\n\td.Set(\"description\", iface.Description)\n\td.Set(\"label\", iface.Label)\n\td.Set(\"type\", iface.Type.Value)\n\td.Set(\"enabled\", iface.Enabled)\n\td.Set(\"mgmtonly\", iface.MgmtOnly)\n\td.Set(\"mtu\", iface.Mtu)\n\td.Set(\"speed\", iface.Speed)\n\tapi.readTags(d, iface.Tags)\n\td.Set(\"tagged_vlans\", getIDsFromNestedVLANDevice(iface.TaggedVlans))\n\td.Set(\"device_id\", iface.Device.ID)\n\n\tif iface.Lag != nil {\n\t\td.Set(\"lag_device_interface_id\", iface.Lag.ID)\n\t}\n\tif iface.Mode != nil {\n\t\td.Set(\"mode\", iface.Mode.Value)\n\t}\n\tif iface.Parent != nil {\n\t\td.Set(\"parent_device_interface_id\", iface.Parent.ID)\n\t}\n\tif iface.UntaggedVlan != nil {\n\t\td.Set(\"untagged_vlan\", iface.UntaggedVlan.ID)\n\t}\n\tif iface.MacAddresses != nil {\n\t\tvar mac_addresses []map[string]interface{}\n\t\tfor i, mac := range iface.MacAddresses {\n\t\t\tvar mac_address = make(map[string]interface{})\n\t\t\t// We just set the first mac address in the `mac_address` attribute\n\t\t\tif i == 0 {\n\t\t\t\td.Set(\"mac_address\", iface.MacAddresses[i].MacAddress)\n\t\t\t}\n\t\t\tmac_address[\"id\"] = mac.ID\n\t\t\tmac_address[\"description\"] = mac.Description\n\t\t\tmac_address[\"mac_address\"] = mac.MacAddress\n\t\t\tmac_addresses = append(mac_addresses, mac_address)\n\t\t}\n\t\td.Set(\"mac_addresses\", mac_addresses)\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxDeviceInterfaceUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tlabel := d.Get(\"label\").(string)\n\tinterfaceType := d.Get(\"type\").(string)\n\tenabled := d.Get(\"enabled\").(bool)\n\tmgmtonly := d.Get(\"mgmtonly\").(bool)\n\tmode := d.Get(\"mode\").(string)\n\ttags, err := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\ttaggedVlans := toInt64List(d.Get(\"tagged_vlans\"))\n\tdeviceID := int64(d.Get(\"device_id\").(int))\n\n\tdata := models.WritableInterface{\n\t\tName:         &name,\n\t\tDescription:  description,\n\t\tLabel:        label,\n\t\tType:         &interfaceType,\n\t\tEnabled:      enabled,\n\t\tMgmtOnly:     mgmtonly,\n\t\tMode:         mode,\n\t\tTags:         tags,\n\t\tTaggedVlans:  taggedVlans,\n\t\tDevice:       &deviceID,\n\t\tWirelessLans: []int64{},\n\t\tVdcs:         []int64{},\n\t}\n\n\tif d.HasChange(\"lag_device_interface_id\") {\n\t\tlag := int64(d.Get(\"lag_device_interface_id\").(int))\n\t\tdata.Lag = &lag\n\t}\n\tif d.HasChange(\"mtu\") {\n\t\tmtu := int64(d.Get(\"mtu\").(int))\n\t\tdata.Mtu = &mtu\n\t}\n\tif d.HasChange(\"parent_device_interface_id\") {\n\t\tparent := int64(d.Get(\"parent_device_interface_id\").(int))\n\t\tdata.Parent = &parent\n\t}\n\tif d.HasChange(\"speed\") {\n\t\tspeed := int64(d.Get(\"speed\").(int))\n\t\tdata.Speed = &speed\n\t}\n\tif d.HasChange(\"untagged_vlan\") {\n\t\tuntaggedvlan := int64(d.Get(\"untagged_vlan\").(int))\n\t\tdata.UntaggedVlan = &untaggedvlan\n\t}\n\n\tparams := dcim.NewDcimInterfacesPartialUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Dcim.DcimInterfacesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxDeviceInterfaceDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimInterfacesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimInterfacesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimInterfacesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\treturn nil\n}\n\nfunc getIDsFromNestedVLANDevice(nestedvlans []*models.NestedVLAN) []int64 {\n\tvar vlans []int64\n\tfor _, vlan := range nestedvlans {\n\t\tvlans = append(vlans, vlan.ID)\n\t}\n\treturn vlans\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_interface_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDeviceInterfaceFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_vlan\" \"test1\" {\n  name = \"%[1]s_vlan1\"\n  vid = 1001\n  tags = []\n}\n\nresource \"netbox_vlan\" \"test2\" {\n  name = \"%[1]s_vlan2\"\n  vid = 1002\n  tags = []\n}`, testName)\n}\n\nfunc testAccNetboxDeviceInterfaceBasic(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_device_interface\" \"test\" {\n  name = \"%s\"\n  device_id = netbox_device.test.id\n  tags = [netbox_tag.test.name]\n  type = \"1000base-t\"\n}`, testName)\n}\n\nfunc testAccNetboxDeviceInterfaceOpts(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_device_interface\" \"test\" {\n  name = \"%[1]s\"\n  description = \"%[1]s\"\n  label = \"%[1]s\"\n  enabled = true\n  mgmtonly = true\n  mtu = 1440\n  device_id = netbox_device.test.id\n  type = \"1000base-t\"\n}`, testName)\n}\n\nfunc testAccNetboxDeviceInterfaceParentAndLAG(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_device_interface\" \"testLAG_parent\" {\n  name = \"%[1]s_parentlag\"\n  device_id = netbox_device.test.id\n  type = \"lag\"\n}\nresource \"netbox_device_interface\" \"testLAG_member1\" {\n  name = \"%[1]s_lagmember1\"\n  device_id = netbox_device.test.id\n  lag_device_interface_id = \"${netbox_device_interface.testLAG_parent.id}\"\n  type = \"25gbase-x-sfp28\"\n}\nresource \"netbox_device_interface\" \"testLAG_member2\" {\n  name = \"%[1]s_lagmember2\"\n  device_id = netbox_device.test.id\n  lag_device_interface_id = \"${netbox_device_interface.testLAG_parent.id}\"\n  type = \"25gbase-x-sfp28\"\n}\nresource \"netbox_device_interface\" \"testparent\" {\n  name = \"%[1]s_parent_parent\"\n  device_id = netbox_device.test.id\n  type = \"25gbase-x-sfp28\"\n}\nresource \"netbox_device_interface\" \"testparent_child1\" {\n  name = \"%[1]s_parent_child\"\n  device_id = netbox_device.test.id\n  parent_device_interface_id = \"${netbox_device_interface.testparent.id}\"\n  type = \"virtual\"\n}\n`, testName)\n}\n\nfunc testAccNetboxDeviceInterfaceVlans(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_device_interface\" \"test1\" {\n  name = \"%[1]s_1\"\n  mode = \"access\"\n  untagged_vlan = netbox_vlan.test1.id\n  device_id = netbox_device.test.id\n  type = \"1000base-t\"\n}\n\nresource \"netbox_device_interface\" \"test2\" {\n  name = \"%[1]s_2\"\n  mode = \"tagged\"\n  tagged_vlans = [netbox_vlan.test2.id]\n  untagged_vlan = netbox_vlan.test1.id\n  device_id = netbox_device.test.id\n  type = \"1000base-t\"\n}\n\nresource \"netbox_device_interface\" \"test3\" {\n  name = \"%[1]s_3\"\n  mode = \"tagged-all\"\n  device_id = netbox_device.test.id\n  type = \"1000base-t\"\n}`, testName)\n}\n\nfunc TestAccNetboxDeviceInterface_basic(t *testing.T) {\n\ttestSlug := \"iface_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxDeviceInterfaceFullDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckDeviceInterfaceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxDeviceInterfaceBasic(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"type\", \"1000base-t\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_interface.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDeviceInterface_parentAndLAG(t *testing.T) {\n\ttestSlug := \"iface_mac\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxDeviceInterfaceFullDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckDeviceInterfaceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxDeviceInterfaceParentAndLAG(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.testLAG_parent\", \"name\", testName+\"_parentlag\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.testLAG_parent\", \"type\", \"lag\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.testLAG_member1\", \"type\", \"25gbase-x-sfp28\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.testLAG_member2\", \"type\", \"25gbase-x-sfp28\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_interface.testLAG_member1\", \"lag_device_interface_id\", \"netbox_device_interface.testLAG_parent\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_interface.testLAG_member2\", \"lag_device_interface_id\", \"netbox_device_interface.testLAG_parent\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.testparent_child1\", \"type\", \"virtual\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_interface.testparent_child1\", \"parent_device_interface_id\", \"netbox_device_interface.testparent\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.testLAG_parent\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.testLAG_member1\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.testLAG_member2\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.testparent\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.testparent_child1\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDeviceInterface_opts(t *testing.T) {\n\ttestSlug := \"iface_mac\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxDeviceInterfaceFullDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckDeviceInterfaceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxDeviceInterfaceOpts(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"type\", \"1000base-t\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"description\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"label\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"enabled\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"mgmtonly\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"mtu\", \"1440\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_interface.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDeviceInterface_vlans(t *testing.T) {\n\ttestSlug := \"iface_vlan\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxDeviceInterfaceFullDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckDeviceInterfaceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxDeviceInterfaceVlans(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test1\", \"mode\", \"access\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test2\", \"mode\", \"tagged\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test3\", \"mode\", \"tagged-all\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_interface.test1\", \"untagged_vlan\", \"netbox_vlan.test1\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_interface.test2\", \"untagged_vlan\", \"netbox_vlan.test1\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_interface.test2\", \"tagged_vlans.0\", \"netbox_vlan.test2\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.test1\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.test2\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_interface.test3\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDeviceInterfaceDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each interface\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_interface\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our interface by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimInterfacesReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimInterfacesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device interface (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimInterfacesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_interface\", &resource.Sweeper{\n\t\tName:         \"netbox_device_interface\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimInterfacesListParams()\n\t\t\tres, err := api.Dcim.DcimInterfacesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, intrface := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*intrface.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimInterfacesDeleteParams().WithID(intrface.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimInterfacesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device interface\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_module_bay.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxDeviceModuleBay() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDeviceModuleBayCreate,\n\t\tRead:   resourceNetboxDeviceModuleBayRead,\n\t\tUpdate: resourceNetboxDeviceModuleBayUpdate,\n\t\tDelete: resourceNetboxDeviceModuleBayDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/modulebay/):\n\n> Module bays represent a space or slot within a device in which a field-replaceable module may be installed. A common example is that of a chassis-based switch such as the Cisco Nexus 9000 or Juniper EX9200. Modules in turn hold additional components that become available to the parent device.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"position\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 30),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceModuleBayCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableModuleBay{\n\t\tDevice:      int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:        strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:       getOptionalStr(d, \"label\", false),\n\t\tPosition:    getOptionalStr(d, \"position\", false),\n\t\tDescription: getOptionalStr(d, \"description\", false),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimModuleBaysCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimModuleBaysCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDeviceModuleBayRead(d, m)\n}\n\nfunc resourceNetboxDeviceModuleBayRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimModuleBaysReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimModuleBaysRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimModuleBaysReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tmoduleBay := res.GetPayload()\n\n\tif moduleBay.Device != nil {\n\t\td.Set(\"device_id\", moduleBay.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", moduleBay.Name)\n\td.Set(\"label\", moduleBay.Label)\n\td.Set(\"position\", moduleBay.Position)\n\td.Set(\"description\", moduleBay.Description)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDeviceModuleBayUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableModuleBay{\n\t\tDevice:      int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:        strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:       getOptionalStr(d, \"label\", true),\n\t\tPosition:    getOptionalStr(d, \"position\", true),\n\t\tDescription: getOptionalStr(d, \"description\", true),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimModuleBaysPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimModuleBaysPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDeviceModuleBayRead(d, m)\n}\n\nfunc resourceNetboxDeviceModuleBayDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimModuleBaysDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimModuleBaysDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_module_bay_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDeviceModuleBayFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n`, testName)\n}\n\nfunc TestAccNetboxDeviceModuleBay_basic(t *testing.T) {\n\ttestSlug := \"device_module_bay_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDeviceModuleBayDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceModuleBayFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  label = \"%[1]s_label\"\n  position = \"testposition\"\n  description = \"%[1]s_description\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"position\", \"testposition\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_module_bay.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceModuleBayFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"label\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"position\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_module_bay.test\", \"tags.#\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_module_bay.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_module_bay.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDeviceModuleBayDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each module bay\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_module_bay\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimModuleBaysReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimModuleBaysRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_module_bay (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimModuleBaysReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_module_bay\", &resource.Sweeper{\n\t\tName:         \"netbox_device_module_bay\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimModuleBaysListParams()\n\t\t\tres, err := api.Dcim.DcimModuleBaysList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, moduleBay := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*moduleBay.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimModuleBaysDeleteParams().WithID(moduleBay.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimModuleBaysDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_module_bay\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_power_feed.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxPowerFeed() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxPowerFeedCreate,\n\t\tRead:   resourceNetboxPowerFeedRead,\n\t\tUpdate: resourceNetboxPowerFeedUpdate,\n\t\tDelete: resourceNetboxPowerFeedDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/powerfeed/):\n\n> A power feed represents the distribution of power from a power panel to a particular device, typically a power distribution unit (PDU). The power port (inlet) on a device can be connected via a cable to a power feed. A power feed may optionally be assigned to a rack to allow more easily tracking the distribution of power among racks.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"power_panel_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tDescription:  \"One of [offline, active, planned, failed]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"offline\", \"active\", \"planned\", \"failed\"}, false),\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tDescription:  \"One of [primary, redundant]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"primary\", \"redundant\"}, false),\n\t\t\t},\n\t\t\t\"supply\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tDescription:  \"One of [ac, dc]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"ac\", \"dc\"}, false),\n\t\t\t},\n\t\t\t\"phase\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tDescription:  \"One of [single-phase, three-phase]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"single-phase\", \"three-phase\"}, false),\n\t\t\t},\n\t\t\t\"voltage\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"amperage\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"max_percent_utilization\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.IntBetween(1, 100),\n\t\t\t},\n\t\t\t\"rack_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_connected\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tDefault:  false,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxPowerFeedCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritablePowerFeed{\n\t\tPowerPanel:     int64ToPtr(int64(d.Get(\"power_panel_id\").(int))),\n\t\tName:           strToPtr(d.Get(\"name\").(string)),\n\t\tStatus:         d.Get(\"status\").(string),\n\t\tType:           d.Get(\"type\").(string),\n\t\tSupply:         d.Get(\"supply\").(string),\n\t\tPhase:          d.Get(\"phase\").(string),\n\t\tVoltage:        int64ToPtr(int64(d.Get(\"voltage\").(int))),\n\t\tAmperage:       int64(d.Get(\"amperage\").(int)),\n\t\tMaxUtilization: int64(d.Get(\"max_percent_utilization\").(int)),\n\t\tRack:           getOptionalInt(d, \"rack_id\"),\n\t\tMarkConnected:  d.Get(\"mark_connected\").(bool),\n\t\tDescription:    getOptionalStr(d, \"description\", false),\n\t\tComments:       getOptionalStr(d, \"comments\", false),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimPowerFeedsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimPowerFeedsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxPowerFeedRead(d, m)\n}\n\nfunc resourceNetboxPowerFeedRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPowerFeedsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimPowerFeedsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimPowerFeedsReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tpowerFeed := res.GetPayload()\n\n\tif powerFeed.PowerPanel != nil {\n\t\td.Set(\"power_panel_id\", powerFeed.PowerPanel.ID)\n\t} else {\n\t\td.Set(\"power_panel_id\", nil)\n\t}\n\n\td.Set(\"name\", powerFeed.Name)\n\n\tif powerFeed.Status != nil {\n\t\td.Set(\"status\", powerFeed.Status.Value)\n\t} else {\n\t\td.Set(\"status\", nil)\n\t}\n\n\tif powerFeed.Type != nil {\n\t\td.Set(\"type\", powerFeed.Type.Value)\n\t} else {\n\t\td.Set(\"type\", nil)\n\t}\n\n\tif powerFeed.Supply != nil {\n\t\td.Set(\"supply\", powerFeed.Supply.Value)\n\t} else {\n\t\td.Set(\"supply\", nil)\n\t}\n\n\tif powerFeed.Phase != nil {\n\t\td.Set(\"phase\", powerFeed.Phase.Value)\n\t} else {\n\t\td.Set(\"phase\", nil)\n\t}\n\n\td.Set(\"voltage\", powerFeed.Voltage)\n\td.Set(\"amperage\", powerFeed.Amperage)\n\td.Set(\"max_percent_utilization\", powerFeed.MaxUtilization)\n\n\tif powerFeed.Rack != nil {\n\t\td.Set(\"rack_id\", powerFeed.Rack.ID)\n\t} else {\n\t\td.Set(\"rack_id\", nil)\n\t}\n\n\td.Set(\"mark_connected\", powerFeed.MarkConnected)\n\td.Set(\"description\", powerFeed.Description)\n\td.Set(\"comments\", powerFeed.Comments)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxPowerFeedUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritablePowerFeed{\n\t\tPowerPanel:     int64ToPtr(int64(d.Get(\"power_panel_id\").(int))),\n\t\tName:           strToPtr(d.Get(\"name\").(string)),\n\t\tStatus:         d.Get(\"status\").(string),\n\t\tType:           d.Get(\"type\").(string),\n\t\tSupply:         d.Get(\"supply\").(string),\n\t\tPhase:          d.Get(\"phase\").(string),\n\t\tVoltage:        int64ToPtr(int64(d.Get(\"voltage\").(int))),\n\t\tAmperage:       int64(d.Get(\"amperage\").(int)),\n\t\tMaxUtilization: int64(d.Get(\"max_percent_utilization\").(int)),\n\t\tRack:           getOptionalInt(d, \"rack_id\"),\n\t\tMarkConnected:  d.Get(\"mark_connected\").(bool),\n\t\tDescription:    getOptionalStr(d, \"description\", true),\n\t\tComments:       getOptionalStr(d, \"comments\", true),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimPowerFeedsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimPowerFeedsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxPowerFeedRead(d, m)\n}\n\nfunc resourceNetboxPowerFeedDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPowerFeedsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimPowerFeedsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_power_feed_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDevicePowerFeedFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_location\" \"test\" {\n\tname = \"%[1]s\"\n\tsite_id =netbox_site.test.id\n}\n\nresource \"netbox_power_panel\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  location_id = netbox_location.test.id\n}\n\nresource \"netbox_rack\" \"test\" {\n  name = \"%[1]s\"\n\tsite_id = netbox_site.test.id\n\tstatus = \"reserved\"\n\twidth = 19\n\tu_height = 48\n\ttenant_id = netbox_tenant.test.id\n\tlocation_id = netbox_location.test.id\n}\n`, testName)\n}\n\nfunc TestAccNetboxDevicePowerFeed_basic(t *testing.T) {\n\ttestSlug := \"device_power_feed_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDevicePowerFeedDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePowerFeedFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_power_feed\" \"test\" {\n\tpower_panel_id = netbox_power_panel.test.id\n\tname = \"%[1]s\"\n\tstatus = \"active\"\n\ttype = \"primary\"\n\tsupply = \"ac\"\n\tphase = \"single-phase\"\n\tvoltage = 250\n\tamperage = 100\n  max_percent_utilization = 80\n\n\track_id = netbox_rack.test.id\n\tmark_connected = true\n\tdescription = \"%[1]s_description\"\n\tcomments = \"%[1]s_comments\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"type\", \"primary\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"supply\", \"ac\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"phase\", \"single-phase\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"voltage\", \"250\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"amperage\", \"100\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"max_percent_utilization\", \"80\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"comments\", testName+\"_comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"mark_connected\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_power_feed.test\", \"power_panel_id\", \"netbox_power_panel.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_power_feed.test\", \"rack_id\", \"netbox_rack.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePowerFeedFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_power_feed\" \"test\" {\n\tpower_panel_id = netbox_power_panel.test.id\n\tname = \"%[1]s\"\n\tstatus = \"active\"\n\ttype = \"primary\"\n\tsupply = \"ac\"\n\tphase = \"single-phase\"\n\tvoltage = 250\n\tamperage = 100\n  max_percent_utilization = 80\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"type\", \"primary\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"supply\", \"ac\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"phase\", \"single-phase\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"voltage\", \"250\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"amperage\", \"100\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"max_percent_utilization\", \"80\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"mark_connected\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_feed.test\", \"rack_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_power_feed.test\", \"power_panel_id\", \"netbox_power_panel.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_power_feed.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDevicePowerFeedDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each power feed\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_power_feed\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimPowerFeedsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimPowerFeedsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_power_feed (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimPowerFeedsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_power_feed\", &resource.Sweeper{\n\t\tName:         \"netbox_power_feed\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimPowerFeedsListParams()\n\t\t\tres, err := api.Dcim.DcimPowerFeedsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, powerFeed := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*powerFeed.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimPowerFeedsDeleteParams().WithID(powerFeed.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimPowerFeedsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a power_feed\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_power_outlet.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxDevicePowerOutlet() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDevicePowerOutletCreate,\n\t\tRead:   resourceNetboxDevicePowerOutletRead,\n\t\tUpdate: resourceNetboxDevicePowerOutletUpdate,\n\t\tDelete: resourceNetboxDevicePowerOutletDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/poweroutlet/):\n\n> Power outlets represent the outlets on a power distribution unit (PDU) or other device that supplies power to dependent devices. Each power port may be assigned a physical type, and may be associated with a specific feed leg (where three-phase power is used) and/or a specific upstream power port. This association can be used to model the distribution of power within a device.\n\nFor example, imagine a PDU with one power port which draws from a three-phase feed and 48 power outlets arranged into three banks of 16 outlets each. Outlets 1-16 would be associated with leg A on the port, and outlets 17-32 and 33-48 would be associated with legs B and C, respectively.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"module_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"One of [iec-60320-c5, iec-60320-c7, iec-60320-c13, iec-60320-c15, iec-60320-c19, iec-60320-c21, iec-60309-p-n-e-4h, iec-60309-p-n-e-6h, iec-60309-p-n-e-9h, iec-60309-2p-e-4h, iec-60309-2p-e-6h, iec-60309-2p-e-9h, iec-60309-3p-e-4h, iec-60309-3p-e-6h, iec-60309-3p-e-9h, iec-60309-3p-n-e-4h, iec-60309-3p-n-e-6h, iec-60309-3p-n-e-9h, nema-1-15r, nema-5-15r, nema-5-20r, nema-5-30r, nema-5-50r, nema-6-15r, nema-6-20r, nema-6-30r, nema-6-50r, nema-10-30r, nema-10-50r, nema-14-20r, nema-14-30r, nema-14-50r, nema-14-60r, nema-15-15r, nema-15-20r, nema-15-30r, nema-15-50r, nema-15-60r, nema-l1-15r, nema-l5-15r, nema-l5-20r, nema-l5-30r, nema-l5-50r, nema-l6-15r, nema-l6-20r, nema-l6-30r, nema-l6-50r, nema-l10-30r, nema-l14-20r, nema-l14-30r, nema-l14-50r, nema-l14-60r, nema-l15-20r, nema-l15-30r, nema-l15-50r, nema-l15-60r, nema-l21-20r, nema-l21-30r, nema-l22-30r, CS6360C, CS6364C, CS8164C, CS8264C, CS8364C, CS8464C, ita-e, ita-f, ita-g, ita-h, ita-i, ita-j, ita-k, ita-l, ita-m, ita-n, ita-o, ita-multistandard, usb-a, usb-micro-b, usb-c, dc-terminal, hdot-cx, saf-d-grid, neutrik-powercon-20a, neutrik-powercon-32a, neutrik-powercon-true1, neutrik-powercon-true1-top, ubiquiti-smartpower, hardwired, other]\",\n\t\t\t},\n\t\t\t\"power_port_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"feed_leg\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tDescription:  \"One of [A, B, C]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"A\", \"B\", \"C\"}, false),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_connected\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tDefault:  false,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDevicePowerOutletCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritablePowerOutlet{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:         getOptionalStr(d, \"label\", false),\n\t\tType:          getOptionalStr(d, \"type\", false),\n\t\tPowerPort:     getOptionalInt(d, \"power_port_id\"),\n\t\tFeedLeg:       getOptionalStr(d, \"feed_leg\", false),\n\t\tDescription:   getOptionalStr(d, \"description\", false),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimPowerOutletsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimPowerOutletsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDevicePowerOutletRead(d, m)\n}\n\nfunc resourceNetboxDevicePowerOutletRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPowerOutletsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimPowerOutletsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimPowerOutletsReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tpowerOutlet := res.GetPayload()\n\n\tif powerOutlet.Device != nil {\n\t\td.Set(\"device_id\", powerOutlet.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", powerOutlet.Name)\n\n\tif powerOutlet.Module != nil {\n\t\td.Set(\"module_id\", powerOutlet.Module.ID)\n\t} else {\n\t\td.Set(\"module_id\", nil)\n\t}\n\n\td.Set(\"label\", powerOutlet.Label)\n\n\tif powerOutlet.Type != nil {\n\t\td.Set(\"type\", powerOutlet.Type.Value)\n\t} else {\n\t\td.Set(\"type\", nil)\n\t}\n\n\tif powerOutlet.PowerPort != nil {\n\t\td.Set(\"power_port_id\", powerOutlet.PowerPort.ID)\n\t} else {\n\t\td.Set(\"power_port_id\", nil)\n\t}\n\n\tif powerOutlet.FeedLeg != nil {\n\t\td.Set(\"feed_leg\", powerOutlet.FeedLeg.Value)\n\t} else {\n\t\td.Set(\"feed_leg\", nil)\n\t}\n\n\td.Set(\"description\", powerOutlet.Description)\n\td.Set(\"mark_connected\", powerOutlet.MarkConnected)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDevicePowerOutletUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritablePowerOutlet{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:         getOptionalStr(d, \"label\", true),\n\t\tType:          getOptionalStr(d, \"type\", false),\n\t\tPowerPort:     getOptionalInt(d, \"power_port_id\"),\n\t\tFeedLeg:       getOptionalStr(d, \"feed_leg\", false),\n\t\tDescription:   getOptionalStr(d, \"description\", true),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimPowerOutletsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimPowerOutletsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDevicePowerOutletRead(d, m)\n}\n\nfunc resourceNetboxDevicePowerOutletDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPowerOutletsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimPowerOutletsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_power_outlet_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDevicePowerOutletFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id = netbox_device.test.id\n  module_bay_id = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status = \"active\"\n}\n\nresource \"netbox_device_power_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxDevicePowerOutlet_basic(t *testing.T) {\n\ttestSlug := \"device_power_outlet_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDevicePowerOutletDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePowerOutletFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_power_outlet\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n\n\tmodule_id = netbox_module.test.id\n\tlabel = \"%[1]s_label\"\n\ttype = \"iec-60320-c5\"\n\tpower_port_id = netbox_device_power_port.test.id\n\tfeed_leg = \"A\"\n\tdescription = \"%[1]s_description\"\n\tmark_connected = true\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"type\", \"iec-60320-c5\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"feed_leg\", \"A\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"mark_connected\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_power_outlet.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_power_outlet.test\", \"module_id\", \"netbox_module.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_power_outlet.test\", \"power_port_id\", \"netbox_device_power_port.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePowerOutletFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_power_outlet\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"label\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"type\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"feed_leg\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"mark_connected\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"module_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_outlet.test\", \"power_port_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_power_outlet.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_power_outlet.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDevicePowerOutletDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each power outlet\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_power_outlet\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimPowerOutletsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimPowerOutletsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_power_outlet (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimPowerOutletsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_power_outlet\", &resource.Sweeper{\n\t\tName:         \"netbox_device_power_outlet\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimPowerOutletsListParams()\n\t\t\tres, err := api.Dcim.DcimPowerOutletsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, powerOutlet := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*powerOutlet.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimPowerOutletsDeleteParams().WithID(powerOutlet.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimPowerOutletsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_power_outlet\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_power_port.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxDevicePowerPort() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDevicePowerPortCreate,\n\t\tRead:   resourceNetboxDevicePowerPortRead,\n\t\tUpdate: resourceNetboxDevicePowerPortUpdate,\n\t\tDelete: resourceNetboxDevicePowerPortDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/powerport/):\n\n> A power port is a device component which draws power from some external source (e.g. an upstream power outlet), and generally represents a power supply internal to a device.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"module_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"One of [iec-60320-c6, iec-60320-c8, iec-60320-c14, iec-60320-c16, iec-60320-c20, iec-60320-c22, iec-60309-p-n-e-4h, iec-60309-p-n-e-6h, iec-60309-p-n-e-9h, iec-60309-2p-e-4h, iec-60309-2p-e-6h, iec-60309-2p-e-9h, iec-60309-3p-e-4h, iec-60309-3p-e-6h, iec-60309-3p-e-9h, iec-60309-3p-n-e-4h, iec-60309-3p-n-e-6h, iec-60309-3p-n-e-9h, nema-1-15p, nema-5-15p, nema-5-20p, nema-5-30p, nema-5-50p, nema-6-15p, nema-6-20p, nema-6-30p, nema-6-50p, nema-10-30p, nema-10-50p, nema-14-20p, nema-14-30p, nema-14-50p, nema-14-60p, nema-15-15p, nema-15-20p, nema-15-30p, nema-15-50p, nema-15-60p, nema-l1-15p, nema-l5-15p, nema-l5-20p, nema-l5-30p, nema-l5-50p, nema-l6-15p, nema-l6-20p, nema-l6-30p, nema-l6-50p, nema-l10-30p, nema-l14-20p, nema-l14-30p, nema-l14-50p, nema-l14-60p, nema-l15-20p, nema-l15-30p, nema-l15-50p, nema-l15-60p, nema-l21-20p, nema-l21-30p, nema-l22-30p, cs6361c, cs6365c, cs8165c, cs8265c, cs8365c, cs8465c, ita-c, ita-e, ita-f, ita-ef, ita-g, ita-h, ita-i, ita-j, ita-k, ita-l, ita-m, ita-n, ita-o, usb-a, usb-b, usb-c, usb-mini-a, usb-mini-b, usb-micro-a, usb-micro-b, usb-micro-ab, usb-3-b, usb-3-micro-b, dc-terminal, saf-d-grid, neutrik-powercon-20, neutrik-powercon-32, neutrik-powercon-true1, neutrik-powercon-true1-top, ubiquiti-smartpower, hardwired, other]\",\n\t\t\t},\n\t\t\t\"maximum_draw\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"allocated_draw\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_connected\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tDefault:  false,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDevicePowerPortCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritablePowerPort{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:         getOptionalStr(d, \"label\", false),\n\t\tType:          getOptionalStr(d, \"type\", false),\n\t\tMaximumDraw:   getOptionalInt(d, \"maximum_draw\"),\n\t\tAllocatedDraw: getOptionalInt(d, \"allocated_draw\"),\n\t\tDescription:   getOptionalStr(d, \"description\", false),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimPowerPortsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimPowerPortsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDevicePowerPortRead(d, m)\n}\n\nfunc resourceNetboxDevicePowerPortRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPowerPortsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimPowerPortsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimPowerPortsReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tpowerPort := res.GetPayload()\n\n\tif powerPort.Device != nil {\n\t\td.Set(\"device_id\", powerPort.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", powerPort.Name)\n\n\tif powerPort.Module != nil {\n\t\td.Set(\"module_id\", powerPort.Module.ID)\n\t} else {\n\t\td.Set(\"module_id\", nil)\n\t}\n\n\td.Set(\"label\", powerPort.Label)\n\n\tif powerPort.Type != nil {\n\t\td.Set(\"type\", powerPort.Type.Value)\n\t} else {\n\t\td.Set(\"type\", nil)\n\t}\n\n\td.Set(\"maximum_draw\", powerPort.MaximumDraw)\n\td.Set(\"allocated_draw\", powerPort.AllocatedDraw)\n\n\td.Set(\"description\", powerPort.Description)\n\td.Set(\"mark_connected\", powerPort.MarkConnected)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDevicePowerPortUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritablePowerPort{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tLabel:         getOptionalStr(d, \"label\", true),\n\t\tType:          getOptionalStr(d, \"type\", false),\n\t\tMaximumDraw:   getOptionalInt(d, \"maximum_draw\"),\n\t\tAllocatedDraw: getOptionalInt(d, \"allocated_draw\"),\n\t\tDescription:   getOptionalStr(d, \"description\", true),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimPowerPortsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimPowerPortsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDevicePowerPortRead(d, m)\n}\n\nfunc resourceNetboxDevicePowerPortDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPowerPortsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimPowerPortsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_power_port_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDevicePowerPortFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id = netbox_device.test.id\n  module_bay_id = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status = \"active\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxDevicePowerPort_basic(t *testing.T) {\n\ttestSlug := \"device_power_port_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDevicePowerPortDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePowerPortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_power_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n\n\tmaximum_draw = 750\n  allocated_draw = 500\n\tmark_connected = true\n\ttype = \"iec-60320-c6\"\n  module_id = netbox_module.test.id\n  description = \"%[1]s_description\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"maximum_draw\", \"750\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"allocated_draw\", \"500\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"type\", \"iec-60320-c6\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"mark_connected\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_power_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_power_port.test\", \"module_id\", \"netbox_module.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePowerPortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_power_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"maximum_draw\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"allocated_draw\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"type\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"mark_connected\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_power_port.test\", \"module_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_power_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_power_port.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDevicePowerPortDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each power port\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_power_port\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimPowerPortsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimPowerPortsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_power_port (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimPowerPortsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_power_port\", &resource.Sweeper{\n\t\tName:         \"netbox_device_power_port\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimPowerPortsListParams()\n\t\t\tres, err := api.Dcim.DcimPowerPortsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, powerPort := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*powerPort.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimPowerPortsDeleteParams().WithID(powerPort.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimPowerPortsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_power_port\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_primary_ip.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxDevicePrimaryIP() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDevicePrimaryIPCreate,\n\t\tRead:   resourceNetboxDevicePrimaryIPRead,\n\t\tUpdate: resourceNetboxDevicePrimaryIPUpdate,\n\t\tDelete: resourceNetboxDevicePrimaryIPDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):This resource is used to define the primary IP for a given device. The primary IP is reflected in the device Netbox UI, which identifies the Primary IPv4 and IPv6 addresses.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"ip_address_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"ip_address_version\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tValidateFunc: validation.IntInSlice([]int{4, 6}),\n\t\t\t\tOptional:     true,\n\t\t\t\tDefault:      4,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDevicePrimaryIPCreate(d *schema.ResourceData, m interface{}) error {\n\td.SetId(strconv.Itoa(d.Get(\"device_id\").(int)))\n\n\treturn resourceNetboxDevicePrimaryIPUpdate(d, m)\n}\n\nfunc resourceNetboxDevicePrimaryIPRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimDevicesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimDevicesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDevicesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tIPAddressVersion := d.Get(\"ip_address_version\")\n\td.Set(\"ip_address_version\", IPAddressVersion)\n\n\tif IPAddressVersion == 4 && res.GetPayload().PrimaryIp4 != nil {\n\t\td.Set(\"ip_address_id\", res.GetPayload().PrimaryIp4.ID)\n\t} else if IPAddressVersion == 6 && res.GetPayload().PrimaryIp6 != nil {\n\t\td.Set(\"ip_address_id\", res.GetPayload().PrimaryIp6.ID)\n\t} else {\n\t\t// if the device exists, but has no primary ip, consider this element deleted\n\t\td.SetId(\"\")\n\t\treturn nil\n\t}\n\td.Set(\"device_id\", res.GetPayload().ID)\n\treturn nil\n}\n\nfunc resourceNetboxDevicePrimaryIPUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdeviceID := int64(d.Get(\"device_id\").(int))\n\tIPAddressID := int64(d.Get(\"ip_address_id\").(int))\n\tIPAddressVersion := int64(d.Get(\"ip_address_version\").(int))\n\n\t// because the go-netbox library does not have patch support atm, we have to get the whole object and re-put it\n\n\t// first, get the device\n\treadParams := dcim.NewDcimDevicesReadParams().WithID(deviceID)\n\tres, err := api.Dcim.DcimDevicesRead(readParams, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdevice := res.GetPayload()\n\n\t// then update the FULL device with ALL tracked attributes\n\tdata := models.WritableDeviceWithConfigContext{}\n\n\tdata.Name = device.Name\n\tdata.Tags = device.Tags\n\t// the netbox API sends the URL property as part of NestedTag, but it does not accept the URL property when we send it back\n\t// so set it to empty\n\t// display too\n\tfor _, tag := range data.Tags {\n\t\ttag.URL = \"\"\n\t\ttag.Display = \"\"\n\t}\n\n\tif device.DeviceType != nil {\n\t\tdata.DeviceType = &device.DeviceType.ID\n\t}\n\n\tif device.Site != nil {\n\t\tdata.Site = &device.Site.ID\n\t}\n\n\tif device.Role != nil {\n\t\tdata.Role = &device.Role.ID\n\t}\n\n\tif device.PrimaryIp4 != nil {\n\t\tdata.PrimaryIp4 = &device.PrimaryIp4.ID\n\t}\n\n\tif device.PrimaryIp6 != nil {\n\t\tdata.PrimaryIp6 = &device.PrimaryIp6.ID\n\t}\n\n\t// unset primary ip address if -1 is passed as id\n\tif IPAddressID == -1 {\n\t\tif IPAddressVersion == 4 {\n\t\t\tdata.PrimaryIp4 = nil\n\t\t} else {\n\t\t\tdata.PrimaryIp6 = nil\n\t\t}\n\t} else {\n\t\tif IPAddressVersion == 4 {\n\t\t\tdata.PrimaryIp4 = &IPAddressID\n\t\t} else {\n\t\t\tdata.PrimaryIp6 = &IPAddressID\n\t\t}\n\t}\n\n\tupdateParams := dcim.NewDcimDevicesPartialUpdateParams().WithID(deviceID).WithData(&data)\n\n\t_, err = api.Dcim.DcimDevicesPartialUpdate(updateParams, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxDevicePrimaryIPRead(d, m)\n}\n\nfunc resourceNetboxDevicePrimaryIPDelete(d *schema.ResourceData, m interface{}) error {\n\t// Set ip_address_id to minus one and go to update. Update will set nil\n\td.Set(\"ip_address_id\", -1)\n\treturn resourceNetboxDevicePrimaryIPUpdate(d, m)\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_primary_ip_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxDevicePrimaryIPFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_location\" \"test\" {\n  name = \"%[1]s\"\n  site_id =netbox_site.test.id\n}\n\nresource \"netbox_rack\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  status = \"reserved\"\n  width = 19\n  u_height = 48\n  tenant_id = netbox_tenant.test.id\n  location_id = netbox_location.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  tenant_id = netbox_tenant.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"thisisacomment\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 10\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_device_interface\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  type = \"1000base-t\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxDevicePrimaryIP4_basic(t *testing.T) {\n\ttestSlug := \"pr_ip_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + `\nresource \"netbox_ip_address\" \"test_v4\" {\n  ip_address = \"1.1.1.12/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4\" {\n  device_id = netbox_device.test.id\n  ip_address_id = netbox_ip_address.test_v4.id\n}`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4\", \"ip_address_id\", \"netbox_ip_address.test_v4\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"status\", \"planned\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDevicePrimaryIP6_basic(t *testing.T) {\n\ttestSlug := \"pr_ipv6_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + `\nresource \"netbox_ip_address\" \"test_v6\" {\n  ip_address = \"2001::1/128\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test.id\n  object_type = \"dcim.interface\"\n}\nresource \"netbox_device_primary_ip\" \"test_v6\" {\n  device_id = netbox_device.test.id\n  ip_address_id = netbox_ip_address.test_v6.id\n  ip_address_version = 6\n}`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v6\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v6\", \"ip_address_id\", \"netbox_ip_address.test_v6\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"status\", \"planned\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDevicePrimaryIP4_removePrimary(t *testing.T) {\n\ttestSlug := \"pr_ip_removePrimary\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test2\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"thisisacomment\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test2\" {\n  device_id = netbox_device.test2.id\n  name = \"%[1]s\"\n  type = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"test_v4_2\" {\n  ip_address = \"1.1.1.16/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test2.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_2\" {\n  device_id = netbox_device.test2.id\n  ip_address_id = netbox_ip_address.test_v4_2.id\n}`, testName),\n\t\t\t},\n\t\t\t// A repeated second step is required, so that the resource \"netbox_device\" \"test2\" goes through a resourceNetboxDeviceRead cycle\n\t\t\t// This is needed because adding a netbox_device_primary_ip updates the netbox_device\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test2\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"thisisacomment\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test2\" {\n  device_id = netbox_device.test2.id\n  name = \"%[1]s\"\n  type = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"test_v4_2\" {\n  ip_address = \"1.1.1.16/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test2.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_2\" {\n  device_id = netbox_device.test2.id\n  ip_address_id = netbox_ip_address.test_v4_2.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_2\", \"device_id\", \"netbox_device.test2\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_2\", \"ip_address_id\", \"netbox_ip_address.test_v4_2\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Now we do 2 things: modify netbox_device.test2 (changing the comment value), AND we remove the IP and primary IP\n\t\t\t// This fails with:\n\t\t\t//        Error: [PUT /dcim/devices/{id}/][400] dcim_devices_update default {\"primary_ip4\":[\"Related object not found using the provided numeric ID: 14\"]}\n\t\t\t// because (I think) that the device is doing 1) a read of the current state, 2) the deletion of the primary IP then modifies the device, 3) the device then tries to write its changes, but its now out of date\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test2\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"thisisacomment with changes\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test2\" {\n  device_id = netbox_device.test2.id\n  name = \"%[1]s\"\n  type = \"1000base-t\"\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test2\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test2\", \"primary_ipv4\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test2\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test2\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test2\", \"status\", \"planned\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDevicePrimaryIP4_simpleUpdateDevice(t *testing.T) {\n\ttestSlug := \"pr_ip_updateDevice\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test3\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment1\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test3\" {\n  device_id = netbox_device.test3.id\n  name = \"%[1]s\"\n  type = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"test_v4_3\" {\n  ip_address = \"1.1.1.101/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test3.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_3\" {\n  device_id = netbox_device.test3.id\n  ip_address_id = netbox_ip_address.test_v4_3.id\n}`, testName),\n\t\t\t},\n\t\t\t// Update the device and check the primary ip value\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test3\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment2\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test3\" {\n  device_id = netbox_device.test3.id\n  name = \"%[1]s\"\n  type = \"virtual\"\n}\n\nresource \"netbox_ip_address\" \"test_v4_3\" {\n  ip_address = \"1.1.1.101/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test3.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_3\" {\n  device_id = netbox_device.test3.id\n  ip_address_id = netbox_ip_address.test_v4_3.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_3\", \"device_id\", \"netbox_device.test3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_3\", \"ip_address_id\", \"netbox_ip_address.test_v4_3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test3\", \"primary_ipv4\", \"netbox_ip_address.test_v4_3\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Update the device and the interface and check the primary ip value\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test3\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment3\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test3\" {\n  device_id = netbox_device.test3.id\n  name = \"%[1]s\"\n  type = \"1000base-t\"\n}\n\nresource \"netbox_ip_address\" \"test_v4_3\" {\n  ip_address = \"1.1.1.101/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test3.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_3\" {\n  device_id = netbox_device.test3.id\n  ip_address_id = netbox_ip_address.test_v4_3.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_3\", \"device_id\", \"netbox_device.test3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_3\", \"ip_address_id\", \"netbox_ip_address.test_v4_3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test3\", \"primary_ipv4\", \"netbox_ip_address.test_v4_3\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Update the device, the interface and the IP address, then check the primary ip\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test3\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment4\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test3\" {\n  device_id = netbox_device.test3.id\n  name = \"%[1]s\"\n  type = \"virtual\"\n}\n\nresource \"netbox_ip_address\" \"test_v4_3\" {\n  ip_address = \"1.1.1.102/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test3.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_3\" {\n  device_id = netbox_device.test3.id\n  ip_address_id = netbox_ip_address.test_v4_3.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_3\", \"device_id\", \"netbox_device.test3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_3\", \"ip_address_id\", \"netbox_ip_address.test_v4_3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test3\", \"primary_ipv4\", \"netbox_ip_address.test_v4_3\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Force a read at the end\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test3\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"commnent4\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test3\" {\n  device_id = netbox_device.test3.id\n  name = \"%[1]s\"\n  type = \"virtual\"\n}\n\nresource \"netbox_ip_address\" \"test_v4_3\" {\n  ip_address = \"1.1.1.102/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test3.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_3\" {\n  device_id = netbox_device.test3.id\n  ip_address_id = netbox_ip_address.test_v4_3.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_3\", \"device_id\", \"netbox_device.test3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_3\", \"ip_address_id\", \"netbox_ip_address.test_v4_3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test3\", \"primary_ipv4\", \"netbox_ip_address.test_v4_3\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDevicePrimaryIP4_refsUpdateDevice(t *testing.T) {\n\ttestSlug := \"pr_ip_refUpdateDevice\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test4\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment1\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test4\" {\n  device_id = netbox_device.test4.id\n  name = \"%[1]s\"\n  type = \"1000base-t\"\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"netbox_ip_address\" \"test_v4_4\" {\n  ip_address = \"1.1.2.101/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test4.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_4\" {\n  device_id = netbox_device.test4.id\n  ip_address_id = netbox_ip_address.test_v4_4.id\n}`, testName),\n\t\t\t},\n\t\t\t// Switch the interface for a new one\n\t\t\t// the create_before_destroy lifecycle ensures the interface exists at all times\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test4\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment1\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test4_2\" {\n  device_id = netbox_device.test4.id\n  name = \"%[1]s-2\"\n  type = \"1000base-t\"\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"netbox_ip_address\" \"test_v4_4\" {\n  ip_address = \"1.1.2.101/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test4_2.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_4\" {\n  device_id = netbox_device.test4.id\n  ip_address_id = netbox_ip_address.test_v4_4.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"device_id\", \"netbox_device.test4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"ip_address_id\", \"netbox_ip_address.test_v4_4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test4\", \"primary_ipv4\", \"netbox_ip_address.test_v4_4\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// switch the ip address for a new one\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test4\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment1\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test4_2\" {\n  device_id = netbox_device.test4.id\n  name = \"%[1]s-2\"\n  type = \"1000base-t\"\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"netbox_ip_address\" \"test_v4_4_2\" {\n  ip_address = \"1.1.2.102/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test4_2.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_4\" {\n  device_id = netbox_device.test4.id\n  ip_address_id = netbox_ip_address.test_v4_4_2.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"device_id\", \"netbox_device.test4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"ip_address_id\", \"netbox_ip_address.test_v4_4_2\", \"id\"),\n\t\t\t\t\t// Needs another read on the device for the field to be accurate\n\t\t\t\t\t//resource.TestCheckResourceAttrPair(\"netbox_device.test4\", \"primary_ipv4\", \"netbox_ip_address.test_v4_4_2\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Force another read to update device\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test4\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment1\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test4_2\" {\n  device_id = netbox_device.test4.id\n  name = \"%[1]s-2\"\n  type = \"1000base-t\"\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"netbox_ip_address\" \"test_v4_4_2\" {\n  ip_address = \"1.1.2.102/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test4_2.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_4\" {\n  device_id = netbox_device.test4.id\n  ip_address_id = netbox_ip_address.test_v4_4_2.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"device_id\", \"netbox_device.test4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"ip_address_id\", \"netbox_ip_address.test_v4_4_2\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test4\", \"primary_ipv4\", \"netbox_ip_address.test_v4_4_2\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Switch both the interface and the ip address at the same time\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test4\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment1\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test4_3\" {\n  device_id = netbox_device.test4.id\n  name = \"%[1]s-3\"\n  type = \"virtual\"\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"netbox_ip_address\" \"test_v4_4_3\" {\n  ip_address = \"1.1.2.103/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test4_3.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_4\" {\n  device_id = netbox_device.test4.id\n  ip_address_id = netbox_ip_address.test_v4_4_3.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"device_id\", \"netbox_device.test4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"ip_address_id\", \"netbox_ip_address.test_v4_4_3\", \"id\"),\n\t\t\t\t\t// Require another read\n\t\t\t\t\t//resource.TestCheckResourceAttrPair(\"netbox_device.test4\", \"primary_ipv4\", \"netbox_ip_address.test_v4_4_3\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Force another read\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test4\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment1\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test4_3\" {\n  device_id = netbox_device.test4.id\n  name = \"%[1]s-3\"\n  type = \"virtual\"\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"netbox_ip_address\" \"test_v4_4_3\" {\n  ip_address = \"1.1.2.103/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test4_3.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_4\" {\n  device_id = netbox_device.test4.id\n  ip_address_id = netbox_ip_address.test_v4_4_3.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"device_id\", \"netbox_device.test4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4\", \"ip_address_id\", \"netbox_ip_address.test_v4_4_3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test4\", \"primary_ipv4\", \"netbox_ip_address.test_v4_4_3\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Make a new primary IP\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDevicePrimaryIPFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test4\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  location_id = netbox_location.test.id\n  comments = \"comment1\"\n  status = \"planned\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 11\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_device_interface\" \"test4_3\" {\n  device_id = netbox_device.test4.id\n  name = \"%[1]s-3\"\n  type = \"virtual\"\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"netbox_ip_address\" \"test_v4_4_3\" {\n  ip_address = \"1.1.2.103/32\"\n  status = \"active\"\n  interface_id = netbox_device_interface.test4_3.id\n  object_type = \"dcim.interface\"\n}\n\nresource \"netbox_device_primary_ip\" \"test_v4_4_2\" {\n  device_id = netbox_device.test4.id\n  ip_address_id = netbox_ip_address.test_v4_4_3.id\n  ip_address_version = 4\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4_2\", \"device_id\", \"netbox_device.test4\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_primary_ip.test_v4_4_2\", \"ip_address_id\", \"netbox_ip_address.test_v4_4_3\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test4\", \"primary_ipv4\", \"netbox_ip_address.test_v4_4_3\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_rear_port.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxDeviceRearPort() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDeviceRearPortCreate,\n\t\tRead:   resourceNetboxDeviceRearPortRead,\n\t\tUpdate: resourceNetboxDeviceRearPortUpdate,\n\t\tDelete: resourceNetboxDeviceRearPortDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/rearport/):\n\n> Like front ports, rear ports are pass-through ports which represent the continuation of a path from one cable to the next. Each rear port is defined with its physical type and a number of positions: Rear ports with more than one position can be mapped to multiple front ports. This can be useful for modeling instances where multiple paths share a common cable (for example, six discrete two-strand fiber connections sharing a 12-strand MPO cable).`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: \"One of [8p8c, 8p6c, 8p4c, 8p2c, 6p6c, 6p4c, 6p2c, 4p4c, 4p2c, gg45, tera-4p, tera-2p, tera-1p, 110-punch, bnc, f, n, mrj21, fc, lc, lc-pc, lc-upc, lc-apc, lsh, lsh-pc, lsh-upc, lsh-apc, mpo, mtrj, sc, sc-pc, sc-upc, sc-apc, st, cs, sn, sma-905, sma-906, urm-p2, urm-p4, urm-p8, splice, other]\",\n\t\t\t},\n\t\t\t\"positions\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"module_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_connected\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tDefault:  false,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceRearPortCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableRearPort{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tType:          strToPtr(d.Get(\"type\").(string)),\n\t\tPositions:     int64(d.Get(\"positions\").(int)),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tLabel:         getOptionalStr(d, \"label\", false),\n\t\tColor:         getOptionalStr(d, \"color_hex\", false),\n\t\tDescription:   getOptionalStr(d, \"description\", false),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimRearPortsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimRearPortsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDeviceRearPortRead(d, m)\n}\n\nfunc resourceNetboxDeviceRearPortRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRearPortsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimRearPortsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRearPortsReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\trearPort := res.GetPayload()\n\n\tif rearPort.Device != nil {\n\t\td.Set(\"device_id\", rearPort.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", rearPort.Name)\n\n\tif rearPort.Type != nil {\n\t\td.Set(\"type\", rearPort.Type.Value)\n\t} else {\n\t\td.Set(\"type\", nil)\n\t}\n\n\td.Set(\"positions\", rearPort.Positions)\n\n\tif rearPort.Module != nil {\n\t\td.Set(\"module_id\", rearPort.Module.ID)\n\t} else {\n\t\td.Set(\"module_id\", nil)\n\t}\n\n\td.Set(\"label\", rearPort.Label)\n\td.Set(\"color_hex\", rearPort.Color)\n\td.Set(\"description\", rearPort.Description)\n\td.Set(\"mark_connected\", rearPort.MarkConnected)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDeviceRearPortUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableRearPort{\n\t\tDevice:        int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:          strToPtr(d.Get(\"name\").(string)),\n\t\tType:          strToPtr(d.Get(\"type\").(string)),\n\t\tPositions:     int64(d.Get(\"positions\").(int)),\n\t\tModule:        getOptionalInt(d, \"module_id\"),\n\t\tLabel:         getOptionalStr(d, \"label\", true),\n\t\tColor:         getOptionalStr(d, \"color_hex\", false),\n\t\tDescription:   getOptionalStr(d, \"description\", true),\n\t\tMarkConnected: d.Get(\"mark_connected\").(bool),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimRearPortsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimRearPortsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDeviceRearPortRead(d, m)\n}\n\nfunc resourceNetboxDeviceRearPortDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRearPortsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimRearPortsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_rear_port_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxDeviceRearPortFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id = netbox_device.test.id\n  module_bay_id = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status = \"active\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxDeviceRearPort_basic(t *testing.T) {\n\ttestSlug := \"device_rear_port_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckDeviceRearPortDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceRearPortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  type = \"8p8c\"\n  positions = 1\n  mark_connected = true\n\n  module_id = netbox_module.test.id\n  label = \"%[1]s_label\"\n  color_hex = \"123456\"\n  description = \"%[1]s_description\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"type\", \"8p8c\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"positions\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"mark_connected\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"color_hex\", \"123456\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_rear_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_rear_port.test\", \"module_id\", \"netbox_module.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceRearPortFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  type = \"8p6c\"\n  positions = 2\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"type\", \"8p6c\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"positions\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"mark_connected\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"label\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"color_hex\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_rear_port.test\", \"module_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_rear_port.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_rear_port.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDeviceRearPortDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each rear port\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device_rear_port\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimRearPortsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimRearPortsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device_rear_port (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimRearPortsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_rear_port\", &resource.Sweeper{\n\t\tName:         \"netbox_device_rear_port\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimRearPortsListParams()\n\t\t\tres, err := api.Dcim.DcimRearPortsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, rearPort := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*rearPort.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimRearPortsDeleteParams().WithID(rearPort.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimRearPortsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_rear_port\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_role.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxDeviceRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDeviceRoleCreate,\n\t\tRead:   resourceNetboxDeviceRoleRead,\n\t\tUpdate: resourceNetboxDeviceRoleUpdate,\n\t\tDelete: resourceNetboxDeviceRoleDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#device-roles):\n\n> Devices can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for core switches, distribution switches, and access switches within your network.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"vm_role\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  true,\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceRoleCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tcolor := d.Get(\"color_hex\").(string)\n\tvmRole := d.Get(\"vm_role\").(bool)\n\tdescription := d.Get(\"description\").(string)\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tparams := dcim.NewDcimDeviceRolesCreateParams().WithData(\n\t\t&models.DeviceRole{\n\t\t\tName:        &name,\n\t\t\tSlug:        &slug,\n\t\t\tColor:       color,\n\t\t\tDescription: description,\n\t\t\tVMRole:      vmRole,\n\t\t\tTags:        tags,\n\t\t},\n\t)\n\n\tres, err := api.Dcim.DcimDeviceRolesCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDeviceRoleRead(d, m)\n}\n\nfunc resourceNetboxDeviceRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimDeviceRolesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimDeviceRolesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDeviceRolesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"vm_role\", res.GetPayload().VMRole)\n\td.Set(\"color_hex\", res.GetPayload().Color)\n\td.Set(\"description\", res.GetPayload().Description)\n\tapi.readTags(d, res.GetPayload().Tags)\n\treturn nil\n}\n\nfunc resourceNetboxDeviceRoleUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.DeviceRole{}\n\n\tname := d.Get(\"name\").(string)\n\tcolor := d.Get(\"color_hex\").(string)\n\tvmRole := d.Get(\"vm_role\").(bool)\n\tdescription := d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.VMRole = vmRole\n\tdata.Color = color\n\tdata.Description = description\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tparams := dcim.NewDcimDeviceRolesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Dcim.DcimDeviceRolesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDeviceRoleRead(d, m)\n}\n\nfunc resourceNetboxDeviceRoleDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimDeviceRolesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimDeviceRolesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDeviceRolesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxDeviceRole_basic(t *testing.T) {\n\ttestSlug := \"dvcrl_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_device_role\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n  color_hex = \"111111\"\n  description = \"Some fancy device role\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_role.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_role.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_role.test\", \"color_hex\", \"111111\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_role.test\", \"description\", \"Some fancy device role\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_role.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDeviceRole_defaultSlug(t *testing.T) {\n\ttestSlug := \"device_role_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_device_role\" \"test\" {\n  name = \"%s\"\n  color_hex = \"111111\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_role.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_role.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_role\", &resource.Sweeper{\n\t\tName:         \"netbox_device_role\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimDeviceRolesListParams()\n\t\t\tres, err := api.Dcim.DcimDeviceRolesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, deviceRole := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*deviceRole.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimDeviceRolesDeleteParams().WithID(deviceRole.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimDeviceRolesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device_role\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc testAccNetboxDeviceFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_location\" \"test\" {\n  name = \"%[1]s\"\n  site_id =netbox_site.test.id\n}\n\nresource \"netbox_rack_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_rack\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  status = \"reserved\"\n  width = 19\n  u_height = 48\n  tenant_id = netbox_tenant.test.id\n  location_id = netbox_location.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_tag\" \"test_b\" {\n  name = \"%[1]sb\"\n}\n\nresource \"netbox_tag\" \"test_c\" {\n  name = \"%[1]sc\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_config_template\" \"test\" {\n  name = \"%[1]s\"\n  template_code = \"hostname {{ name }}\"\n}`, testName)\n}\n\nfunc TestAccNetboxDevice_basic(t *testing.T) {\n\ttestSlug := \"device_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckDeviceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  asset_tag = \"TAGGEDITAGGEDITAG\"\n  comments = \"thisisacomment\"\n  description = \"thisisadescription\"\n  tenant_id = netbox_tenant.test.id\n  platform_id = netbox_platform.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  tags = [netbox_tag.test_a.name]\n  site_id = netbox_site.test.id\n  cluster_id = netbox_cluster.test.id\n  location_id = netbox_location.test.id\n  config_template_id = netbox_config_template.test.id\n  status = \"staged\"\n  serial = \"ABCDEF\"\n  rack_id = netbox_rack.test.id\n  rack_face = \"front\"\n  rack_position = 10\n  local_context_data = jsonencode({\"context_string\"=\"context_value\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"rack_id\", \"netbox_rack.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"config_template_id\", \"netbox_config_template.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"asset_tag\", \"TAGGEDITAGGEDITAG\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"description\", \"thisisadescription\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"status\", \"staged\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"serial\", \"ABCDEF\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"rack_face\", \"front\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"rack_position\", \"10\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  asset_tag = \"TAGGEDITAGGEDITAG_TAGGEDITAGGEDITAGGEDITAG\"\n  comments = \"thisisacomment\"\n  description = \"thisisadescription\"\n  tenant_id = netbox_tenant.test.id\n  platform_id = netbox_platform.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  tags = [netbox_tag.test_a.name]\n  site_id = netbox_site.test.id\n  cluster_id = netbox_cluster.test.id\n  location_id = netbox_location.test.id\n  config_template_id = netbox_config_template.test.id\n  rack_id = netbox_rack.test.id\n  status = \"staged\"\n  serial = \"ABCDEF\"\n  local_context_data = jsonencode({\"context_string\"=\"context_value2\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"rack_id\", \"netbox_rack.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"config_template_id\", \"netbox_config_template.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"asset_tag\", \"TAGGEDITAGGEDITAG_TAGGEDITAGGEDITAGGEDITAG\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"description\", \"thisisadescription\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"status\", \"staged\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"serial\", \"ABCDEF\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"rack_face\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"rack_position\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value2\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  asset_tag = \"TAGGEDITAGGEDITAG\"\n  comments = \"thisisacomment\"\n  description = \"thisisadescription\"\n  tenant_id = netbox_tenant.test.id\n  platform_id = netbox_platform.test.id\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  tags = [netbox_tag.test_a.name]\n  site_id = netbox_site.test.id\n  cluster_id = netbox_cluster.test.id\n  location_id = netbox_location.test.id\n  config_template_id = netbox_config_template.test.id\n  status = \"staged\"\n  serial = \"ABCDEF\"\n  local_context_data = jsonencode({\"context_string\"=\"context_value\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"config_template_id\", \"netbox_config_template.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"asset_tag\", \"TAGGEDITAGGEDITAG\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"description\", \"thisisadescription\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"status\", \"staged\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"serial\", \"ABCDEF\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"rack_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"rack_face\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"rack_position\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  cluster_id = netbox_cluster.test.id\n  platform_id = netbox_platform.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxDevice_virtual_chassis(t *testing.T) {\n\ttestSlug := \"device_virtual_chassis\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckDeviceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_chassis\" \"test\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name]\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  platform_id = netbox_platform.test.id\n  virtual_chassis_id = netbox_virtual_chassis.test.id\n  virtual_chassis_position = 1\n  virtual_chassis_master = true\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_chassis.test\", \"id\", \"netbox_device.test\", \"virtual_chassis_id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"virtual_chassis_master\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"virtual_chassis_position\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_chassis\" \"test\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name]\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  platform_id = netbox_platform.test.id\n  virtual_chassis_id = netbox_virtual_chassis.test.id\n  virtual_chassis_position = 1\n  virtual_chassis_master = false\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"virtual_chassis_master\", \"false\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_chassis\" \"test\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name]\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  platform_id = netbox_platform.test.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device.test\", \"virtual_chassis_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxDeviceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_chassis\" \"test\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name]\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  platform_id = netbox_platform.test.id\n  virtual_chassis_id = netbox_virtual_chassis.test.id\n  virtual_chassis_position = 1\n  virtual_chassis_master = true\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device.test\", \"virtual_chassis_id\", \"netbox_virtual_chassis.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckDeviceDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each device\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_device\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimDevicesReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimDevicesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"device (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimDevicesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device\", &resource.Sweeper{\n\t\tName:         \"netbox_device\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimDevicesListParams()\n\t\t\tres, err := api.Dcim.DcimDevicesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, Device := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*Device.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimDevicesDeleteParams().WithID(Device.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimDevicesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_type.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxDeviceType() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxDeviceTypeCreate,\n\t\tRead:   resourceNetboxDeviceTypeRead,\n\t\tUpdate: resourceNetboxDeviceTypeUpdate,\n\t\tDelete: resourceNetboxDeviceTypeDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/device-types/#device-types_1):\n\n> A device type represents a particular make and model of hardware that exists in the real world. Device types define the physical attributes of a device (rack height and depth) and its individual components (console, power, network interfaces, and so on).`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"model\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"manufacturer_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"part_number\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"u_height\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  \"1.0\",\n\t\t\t},\n\t\t\t\"is_full_depth\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"subdevice_role\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxDeviceTypeCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableDeviceType{}\n\n\tmodel := d.Get(\"model\").(string)\n\tdata.Model = &model\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(model))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tmanufacturerIDValue, ok := d.GetOk(\"manufacturer_id\")\n\tif ok {\n\t\tdata.Manufacturer = int64ToPtr(int64(manufacturerIDValue.(int)))\n\t}\n\n\tif partNo, ok := d.GetOk(\"part_number\"); ok {\n\t\tdata.PartNumber = partNo.(string)\n\t}\n\n\t//Needed to account for 0 u_height values\n\tuHeightValue := d.Get(\"u_height\")\n\tdata.UHeight = float64ToPtr(uHeightValue.(float64))\n\n\tif isFullDepthValue, ok := d.GetOk(\"is_full_depth\"); ok {\n\t\tdata.IsFullDepth = isFullDepthValue.(bool)\n\t}\n\n\tif subdeviceRoleValue, ok := d.GetOk(\"subdevice_role\"); ok {\n\t\tdata.SubdeviceRole = subdeviceRoleValue.(string)\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := dcim.NewDcimDeviceTypesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimDeviceTypesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxDeviceTypeRead(d, m)\n}\n\nfunc resourceNetboxDeviceTypeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimDeviceTypesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimDeviceTypesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDeviceTypesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tdeviceType := res.GetPayload()\n\td.Set(\"model\", deviceType.Model)\n\td.Set(\"slug\", deviceType.Slug)\n\td.Set(\"manufacturer_id\", deviceType.Manufacturer.ID)\n\td.Set(\"part_number\", deviceType.PartNumber)\n\td.Set(\"u_height\", deviceType.UHeight)\n\td.Set(\"is_full_depth\", deviceType.IsFullDepth)\n\tif deviceType.SubdeviceRole != nil && deviceType.SubdeviceRole.Value != nil {\n\t\td.Set(\"subdevice_role\", *deviceType.SubdeviceRole.Value)\n\t} else {\n\t\td.Set(\"subdevice_role\", \"\")\n\t}\n\tapi.readTags(d, deviceType.Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxDeviceTypeUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableDeviceType{}\n\n\tmodel := d.Get(\"model\").(string)\n\tdata.Model = &model\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(model))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tmanufacturerIDValue, ok := d.GetOk(\"manufacturer_id\")\n\tif ok {\n\t\tdata.Manufacturer = int64ToPtr(int64(manufacturerIDValue.(int)))\n\t}\n\n\tif partNo, ok := d.GetOk(\"part_number\"); ok {\n\t\tdata.PartNumber = partNo.(string)\n\t}\n\n\tuHeightValue := d.Get(\"u_height\")\n\tdata.UHeight = float64ToPtr(uHeightValue.(float64))\n\n\tif isFullDepthValue, ok := d.GetOk(\"is_full_depth\"); ok {\n\t\tdata.IsFullDepth = isFullDepthValue.(bool)\n\t}\n\n\tif subdeviceRoleValue, ok := d.GetOk(\"subdevice_role\"); ok {\n\t\tdata.SubdeviceRole = subdeviceRoleValue.(string)\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := dcim.NewDcimDeviceTypesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimDeviceTypesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxDeviceTypeRead(d, m)\n}\n\nfunc resourceNetboxDeviceTypeDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimDeviceTypesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimDeviceTypesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimDeviceTypesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_device_type_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxDeviceType_basic(t *testing.T) {\n\ttestSlug := \"device_type\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  slug = \"%[2]s\"\n  part_number = \"%[2]s\"\n  u_height = \"0.5\"\n  manufacturer_id = netbox_manufacturer.test.id\n  is_full_depth = true\n  subdevice_role = \"parent\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"model\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"part_number\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"u_height\", \"0.5\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_type.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"is_full_depth\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"subdevice_role\", \"parent\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  slug = \"%[2]s\"\n  part_number = \"%[2]s\"\n  u_height = \"0\"\n  manufacturer_id = netbox_manufacturer.test.id\n  is_full_depth = false\n  subdevice_role = \"child\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"model\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"part_number\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"u_height\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_device_type.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"is_full_depth\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_type.test\", \"subdevice_role\", \"child\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_device_type.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_device_type\", &resource.Sweeper{\n\t\tName:         \"netbox_device_type\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimDeviceTypesListParams()\n\t\t\tres, err := api.Dcim.DcimDeviceTypesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, devicetype := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*devicetype.Model, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimDeviceTypesDeleteParams().WithID(devicetype.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimDeviceTypesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device type\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_event_rule.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxEventRuleActionTypeOptions = []string{\"webhook\", \"script\"}\n\nvar resourceNetboxEventRuleActionTypeToObjectType = map[string]string{\n\t\"webhook\": \"extras.webhook\",\n\t\"script\":  \"extras.script\",\n}\n\nfunc resourceNetboxEventRule() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxEventRuleCreate,\n\t\tRead:   resourceNetboxEventRuleRead,\n\t\tUpdate: resourceNetboxEventRuleUpdate,\n\t\tDelete: resourceNetboxEventRuleDelete,\n\n\t\tDescription: `:meta:subcategory:Extras:From the [official documentation](https://docs.netbox.dev/en/stable/features/event-rules/):\n\n> NetBox can be configured via Event Rules to transmit outgoing webhooks to remote systems in response to internal object changes. The receiver can act on the data in these webhook messages to perform related tasks.\n\tEvent rules can also execute custom scripts, enabling NetBox to run defined logic locally in response to object changes.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"content_types\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tRequired: true,\n\t\t\t\tElem:     &schema.Schema{Type: schema.TypeString},\n\t\t\t},\n\t\t\t\"event_types\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tRequired: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t// We do not enforce event-type validation, because plugins might extend the list of valid events\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t\tDescription: \"The types of event which will trigger this rule. By default, valid values are `object_created`, `oject_updated`, `object_deleted`, `job_started`, `job_completed`, `job_failed` and `job_errored`\",\n\t\t\t},\n\t\t\t\"enabled\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  true,\n\t\t\t},\n\t\t\t\"conditions\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDiffSuppressFunc: func(k, oldValue, newValue string, d *schema.ResourceData) bool {\n\t\t\t\t\tequal, _ := jsonSemanticCompare(oldValue, newValue)\n\t\t\t\t\treturn equal\n\t\t\t\t},\n\t\t\t\tDiffSuppressOnRefresh: true,\n\t\t\t},\n\t\t\t\"action_type\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxEventRuleActionTypeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxEventRuleActionTypeOptions),\n\t\t\t},\n\t\t\t\"action_object_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxEventRuleCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := &models.WritableEventRule{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tactionType := d.Get(\"action_type\").(string)\n\tdata.ActionType = actionType\n\tdata.Description = getOptionalStr(d, \"description\", false)\n\n\tif objectType, ok := resourceNetboxEventRuleActionTypeToObjectType[actionType]; ok {\n\t\tdata.ActionObjectType = strToPtr(objectType)\n\t}\n\n\teventTypes := make([]string, 0)\n\tfor _, eventType := range d.Get(\"event_types\").(*schema.Set).List() {\n\t\teventTypes = append(eventTypes, eventType.(string))\n\t}\n\tdata.EventTypes = eventTypes\n\n\tenabled := d.Get(\"enabled\").(bool)\n\tdata.Enabled = enabled\n\tdata.ActionObjectID = getOptionalInt(d, \"action_object_id\")\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tctypes := d.Get(\"content_types\").(*schema.Set).List()\n\tobjectTypes := make([]string, 0, len(ctypes))\n\tfor _, contentType := range d.Get(\"content_types\").(*schema.Set).List() {\n\t\tobjectTypes = append(objectTypes, contentType.(string))\n\t}\n\tdata.ObjectTypes = objectTypes\n\n\tif conditionsData, ok := d.GetOk(\"conditions\"); ok {\n\t\tvar conditions any\n\t\terr := json.Unmarshal([]byte(conditionsData.(string)), &conditions)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdata.Conditions = conditions\n\t}\n\n\tparams := extras.NewExtrasEventRulesCreateParams().WithData(data)\n\n\tres, err := api.Extras.ExtrasEventRulesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxEventRuleRead(d, m)\n}\n\nfunc resourceNetboxEventRuleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasEventRulesReadParams().WithID(id)\n\n\tres, err := api.Extras.ExtrasEventRulesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasEventRulesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\teventRule := res.GetPayload()\n\td.Set(\"name\", eventRule.Name)\n\td.Set(\"description\", eventRule.Description)\n\td.Set(\"action_type\", eventRule.ActionType.Value)\n\td.Set(\"content_types\", eventRule.ObjectTypes)\n\td.Set(\"event_types\", eventRule.EventTypes)\n\n\td.Set(\"enabled\", eventRule.Enabled)\n\td.Set(\"action_object_id\", eventRule.ActionObjectID)\n\n\tif eventRule.Conditions != nil {\n\t\tconditions, err := json.Marshal(eventRule.Conditions)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\td.Set(\"conditions\", string(conditions))\n\t}\n\n\tapi.readTags(d, eventRule.Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxEventRuleUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableEventRule{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tactionType := d.Get(\"action_type\").(string)\n\tdata.ActionType = actionType\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\n\tif objectType, ok := resourceNetboxEventRuleActionTypeToObjectType[actionType]; ok {\n\t\tdata.ActionObjectType = strToPtr(objectType)\n\t}\n\n\teventTypes := make([]string, 0)\n\tfor _, eventType := range d.Get(\"event_types\").(*schema.Set).List() {\n\t\teventTypes = append(eventTypes, eventType.(string))\n\t}\n\tdata.EventTypes = eventTypes\n\n\tenabled := d.Get(\"enabled\").(bool)\n\tdata.Enabled = enabled\n\tdata.ActionObjectID = getOptionalInt(d, \"action_object_id\")\n\n\tif conditionsData, ok := d.GetOk(\"conditions\"); ok {\n\t\tvar conditions any\n\t\terr := json.Unmarshal([]byte(conditionsData.(string)), &conditions)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdata.Conditions = conditions\n\t}\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tctypes := d.Get(\"content_types\").(*schema.Set).List()\n\tobjectTypes := make([]string, 0, len(ctypes))\n\tfor _, contentType := range d.Get(\"content_types\").(*schema.Set).List() {\n\t\tobjectTypes = append(objectTypes, contentType.(string))\n\t}\n\tdata.ObjectTypes = objectTypes\n\n\tparams := extras.NewExtrasEventRulesUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Extras.ExtrasEventRulesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxEventRuleRead(d, m)\n}\n\nfunc resourceNetboxEventRuleDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasEventRulesDeleteParams().WithID(id)\n\n\t_, err := api.Extras.ExtrasEventRulesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasEventRulesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_event_rule_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc TestAccNetboxEventRule_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"evt_rule_basic\")\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckNetBoxEventRuleDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_webhook\" \"test\" {\n  name        = \"%[1]s\"\n  payload_url = \"https://example.com/webhook\"\n}\n\nresource \"netbox_event_rule\" \"test\" {\n  name             = \"%[1]s\"\n  description      = \"foo description\"\n  content_types    = [\"dcim.site\"]\n  action_type      = \"webhook\"\n  action_object_id = netbox_webhook.test.id\n  event_types      = [\"object_created\", \"object_updated\", \"object_deleted\", \"job_started\", \"job_completed\", \"job_failed\", \"job_errored\"]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"content_types.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"content_types.0\", \"dcim.site\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"action_type\", \"webhook\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"description\", \"foo description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"event_types.#\", \"7\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_webhook\" \"test\" {\n  name        = \"%[1]s\"\n  payload_url = \"https://example.com/webhook\"\n}\n\nresource \"netbox_event_rule\" \"test\" {\n  name             = \"%[1]s\"\n  content_types    = [\"dcim.site\", \"virtualization.cluster\"]\n  action_type      = \"webhook\"\n  action_object_id = netbox_webhook.test.id\n  event_types      = [\"object_created\"]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"content_types.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"content_types.0\", \"dcim.site\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"content_types.1\", \"virtualization.cluster\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"action_type\", \"webhook\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_event_rule.test\", \"event_types.#\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_event_rule.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckNetBoxEventRuleDestroy(s *terraform.State) error {\n\tclient := testAccProvider.Meta().(*providerState)\n\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_event_rule\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Fetch the eventRule by ID\n\t\t// Retrieve our interface by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\teventRule, err := client.Extras.ExtrasEventRulesRead(extras.NewExtrasEventRulesReadParams().WithID(stateID), nil)\n\t\tif err == nil && eventRule != nil {\n\t\t\treturn fmt.Errorf(\"EventRule %s still exists\", rs.Primary.ID)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_event_rule\", &resource.Sweeper{\n\t\tName:         \"netbox_event_rule\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := extras.NewExtrasEventRulesListParams()\n\t\t\tres, err := api.Extras.ExtrasEventRulesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, eventRule := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*eventRule.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := extras.NewExtrasEventRulesDeleteParams().WithID(eventRule.ID)\n\t\t\t\t\t_, err := api.Extras.ExtrasEventRulesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a eventRule\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_group.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/users\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxGroupCreate,\n\t\tRead:   resourceNetboxGroupRead,\n\t\tUpdate: resourceNetboxGroupUpdate,\n\t\tDelete: resourceNetboxGroupDelete,\n\n\t\tDescription: `:meta:subcategory:Authentication:This resource is used to manage groups.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  \"\",\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\nfunc resourceNetboxGroupCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.Group{}\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Name = &name\n\tdata.Description = description\n\n\tparams := users.NewUsersGroupsCreateParams().WithData(&data)\n\tres, err := api.Users.UsersGroupsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxGroupRead(d, m)\n}\n\nfunc resourceNetboxGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := users.NewUsersGroupsReadParams().WithID(id)\n\n\tres, err := api.Users.UsersGroupsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*users.UsersGroupsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tif res.GetPayload().Name != nil {\n\t\td.Set(\"name\", res.GetPayload().Name)\n\t}\n\td.Set(\"description\", res.GetPayload().Description)\n\n\treturn nil\n}\n\nfunc resourceNetboxGroupUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.Group{}\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Name = &name\n\tdata.Description = description\n\n\tparams := users.NewUsersGroupsUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Users.UsersGroupsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxGroupRead(d, m)\n}\n\nfunc resourceNetboxGroupDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := users.NewUsersGroupsDeleteParams().WithID(id)\n\t_, err := api.Users.UsersGroupsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*users.UsersGroupsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/users\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxGroup_basic(t *testing.T) {\n\ttestSlug := \"groups\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_group\" \"test_basic\" {\n  name = \"%s\"\n\tdescription = \"This is my example resource\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_group.test_basic\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_group.test_basic\", \"description\", \"This is my example resource\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_group.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: false,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_group\", &resource.Sweeper{\n\t\tName:         \"netbox_group\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := users.NewUsersGroupsListParams()\n\t\t\tres, err := api.Users.UsersGroupsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, group := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*group.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := users.NewUsersGroupsDeleteParams().WithID(group.ID)\n\t\t\t\t\t_, err := api.Users.UsersGroupsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a group\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_interface.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/go-openapi/runtime\"\n\t\"github.com/go-openapi/strfmt\"\n\t\"github.com/go-viper/mapstructure/v2\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxInterfaceModeOptions = []string{\"access\", \"tagged\", \"tagged-all\"}\n\nfunc resourceNetboxInterface() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxInterfaceCreate,\n\t\tReadContext:   resourceNetboxInterfaceRead,\n\t\tUpdateContext: resourceNetboxInterfaceUpdate,\n\t\tDeleteContext: resourceNetboxInterfaceDelete,\n\n\t\tDescription: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#interfaces):\n\n> Virtual machine interfaces behave similarly to device interfaces, and can be assigned to VRFs, and may have IP addresses, VLANs, and services attached to them. However, given their virtual nature, they lack properties pertaining to physical attributes. For example, VM interfaces do not have a physical type and cannot have cables attached to them.`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"virtual_machine_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"enabled\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  true,\n\t\t\t},\n\t\t\t\"mac_address\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.IsMACAddress,\n\t\t\t\t// Netbox converts MAC addresses always to uppercase\n\t\t\t\tDiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {\n\t\t\t\t\treturn strings.EqualFold(old, new)\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"mode\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxInterfaceModeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxInterfaceModeOptions),\n\t\t\t},\n\t\t\t\"mtu\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.IntBetween(1, 65536),\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:       schema.TypeString,\n\t\t\t\tOptional:   true,\n\t\t\t\tDeprecated: \"This attribute is not supported by netbox any longer. It will be removed in future versions of this provider.\",\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"tagged_vlans\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"untagged_vlan\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"bridge_interface_id\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"ID of the bridge interface this interface belongs to\",\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxInterfaceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tenabled := d.Get(\"enabled\").(bool)\n\tmode := d.Get(\"mode\").(string)\n\ttags, err := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\ttaggedVlans := toInt64List(d.Get(\"tagged_vlans\"))\n\tvirtualMachineID := int64(d.Get(\"virtual_machine_id\").(int))\n\n\tdata := models.WritableVMInterface{\n\t\tName:           &name,\n\t\tDescription:    description,\n\t\tEnabled:        enabled,\n\t\tMode:           mode,\n\t\tTags:           tags,\n\t\tTaggedVlans:    taggedVlans,\n\t\tVirtualMachine: &virtualMachineID,\n\t}\n\tif macAddress := d.Get(\"mac_address\").(string); macAddress != \"\" {\n\t\tdata.MacAddress = &macAddress\n\t}\n\tif mtu, ok := d.Get(\"mtu\").(int); ok && mtu != 0 {\n\t\tdata.Mtu = int64ToPtr(int64(mtu))\n\t}\n\tif untaggedVlan, ok := d.Get(\"untagged_vlan\").(int); ok && untaggedVlan != 0 {\n\t\tdata.UntaggedVlan = int64ToPtr(int64(untaggedVlan))\n\t}\n\tif bridgeIF, ok := d.Get(\"bridge_interface_id\").(int); ok && bridgeIF != 0 {\n\t\tdata.Bridge = int64ToPtr(int64(bridgeIF))\n\t}\n\tparams := virtualization.NewVirtualizationInterfacesCreateParams().WithData(&data)\n\n\tres, err := api.Virtualization.VirtualizationInterfacesCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn diags\n}\n\nfunc resourceNetboxInterfaceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tvar diags diag.Diagnostics\n\n\tparams := virtualization.NewVirtualizationInterfacesReadParams().WithID(id)\n\n\tres, err := api.Virtualization.VirtualizationInterfacesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationInterfacesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\tiface := res.GetPayload()\n\n\td.Set(\"name\", iface.Name)\n\td.Set(\"description\", iface.Description)\n\td.Set(\"enabled\", iface.Enabled)\n\td.Set(\"mac_address\", iface.MacAddress)\n\td.Set(\"mtu\", iface.Mtu)\n\tapi.readTags(d, iface.Tags)\n\td.Set(\"tagged_vlans\", getIDsFromNestedVLAN(iface.TaggedVlans))\n\td.Set(\"virtual_machine_id\", iface.VirtualMachine.ID)\n\n\tif iface.Mode != nil {\n\t\td.Set(\"mode\", iface.Mode.Value)\n\t}\n\tif iface.UntaggedVlan != nil {\n\t\td.Set(\"untagged_vlan\", iface.UntaggedVlan.ID)\n\t}\n\tif iface.Bridge != nil {\n\t\td.Set(\"bridge_interface_id\", iface.Bridge.ID)\n\t} else {\n\t\td.Set(\"bridge_interface_id\", nil)\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxInterfaceUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tenabled := d.Get(\"enabled\").(bool)\n\tmode := d.Get(\"mode\").(string)\n\ttags, err := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\ttaggedVlans := toInt64List(d.Get(\"tagged_vlans\"))\n\tvirtualMachineID := int64(d.Get(\"virtual_machine_id\").(int))\n\n\tdata := models.WritableVMInterface{\n\t\tName:           &name,\n\t\tDescription:    description,\n\t\tEnabled:        enabled,\n\t\tMode:           mode,\n\t\tTags:           tags,\n\t\tTaggedVlans:    taggedVlans,\n\t\tVirtualMachine: &virtualMachineID,\n\t}\n\n\tif d.HasChange(\"mac_address\") {\n\t\tmacAddress := d.Get(\"mac_address\").(string)\n\t\tdata.MacAddress = &macAddress\n\t}\n\tif d.HasChange(\"mtu\") {\n\t\tmtu := int64(d.Get(\"mtu\").(int))\n\t\tdata.Mtu = &mtu\n\t}\n\tif d.HasChange(\"untagged_vlan\") {\n\t\tuntaggedvlan := int64(d.Get(\"untagged_vlan\").(int))\n\t\tdata.UntaggedVlan = &untaggedvlan\n\t}\n\n\t// About the `nullFields` hack\n\t//\n\t// Without this hack, the `bridge_interface_id` field can never be unset\n\t// in the Netbox API once it has been set. This likely also applies to other\n\t// fields, but for now, this is only solved for this field. It can be extended\n\t// though.\n\t//\n\t// Why is it needed?\n\t//\n\t// This method uses VirtualizationInterfacesPartialUpdate which takes similar\n\t// parameters as Create/Update, but will only apply changes to fields that are\n\t// supplied in the JSON payload.\n\t//\n\t// Example:\n\t// - `{ \"bridge\": 123 }` - will set the field\n\t// - `{ \"bridge\": null }` - will unset the field\n\t// - `{}` - will make no changes\n\t//\n\t// Unfortunately with how the Netbox API client is generated, there is no way\n\t// to produce the second example. If you set the field `Bridge` to `nil` it\n\t// will produce JSON without the field present. This is because of the\n\t// `omitempty` struct tag on the field. Which is something you need to make\n\t// partial updates work, but prevents you from unsetting the field.\n\t// There is simply no way to represent this case in Go without introducing\n\t// a special wrapper type that can represent all 3 states.\n\t// (Note that sending `\"bridge\": 0` is not accepted by the API.)\n\t//\n\t// The way this is solved is on the serialization level.\n\t// With `hackSerializeAsNull` I made a serialization middleware of sorts that\n\t// will serialize an explicit `null` value for field names given in the slice.\n\n\tvar nullFields []string\n\tif d.HasChange(\"bridge_interface_id\") {\n\t\tifID := int64(d.Get(\"bridge_interface_id\").(int))\n\t\tdata.Bridge = &ifID\n\t\tif ifID == 0 {\n\t\t\tnullFields = append(nullFields, \"bridge\")\n\t\t}\n\t}\n\n\tparams := virtualization.NewVirtualizationInterfacesPartialUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Virtualization.VirtualizationInterfacesPartialUpdate(params, nil, hackSerializeAsNull(nullFields...))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn resourceNetboxInterfaceRead(ctx, d, m)\n}\n\nfunc resourceNetboxInterfaceDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationInterfacesDeleteParams().WithID(id)\n\n\t_, err := api.Virtualization.VirtualizationInterfacesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationInterfacesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\treturn nil\n}\n\nfunc getIDsFromNestedVLAN(nestedvlans []*models.NestedVLAN) []int64 {\n\tvar vlans []int64\n\tfor _, vlan := range nestedvlans {\n\t\tvlans = append(vlans, vlan.ID)\n\t}\n\treturn vlans\n}\n\ntype interceptWriter struct {\n\truntime.ClientRequest\n\tfields []string\n}\n\nfunc (iw interceptWriter) SetBodyParam(p any) error {\n\tout := make(map[string]any)\n\tdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{\n\t\tTagName: \"json\",\n\t\tResult:  &out,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := dec.Decode(p); err != nil {\n\t\treturn err\n\t}\n\tfor _, fieldName := range iw.fields {\n\t\t_, ok := out[fieldName]\n\t\tif ok {\n\t\t\tout[fieldName] = nil\n\t\t}\n\t}\n\treturn iw.ClientRequest.SetBodyParam(out)\n}\n\ntype interceptParams struct {\n\tinner  runtime.ClientRequestWriter\n\tfields []string\n}\n\n// WriteToRequest implements [runtime.ClientRequestWriter].\nfunc (ip interceptParams) WriteToRequest(req runtime.ClientRequest, reg strfmt.Registry) error {\n\twriter := interceptWriter{ClientRequest: req, fields: ip.fields}\n\treturn ip.inner.WriteToRequest(writer, reg)\n}\n\n// hackSerializeAsNull is a serialization middleware of sorts that will\n// serialize an explicit `null` value for all field names given in the slice.\n//\n// It does this by first serializing the params from a struct to a map\n// and then sets the value for given fields to `nil`.\n// With this the field will definitely be serialized and not omitted when set\n// to `nil`.\nfunc hackSerializeAsNull(fields ...string) virtualization.ClientOption {\n\treturn func(co *runtime.ClientOperation) {\n\t\toriginalParams := co.Params\n\t\tco.Params = interceptParams{inner: originalParams, fields: fields}\n\t}\n}\n"
  },
  {
    "path": "netbox/resource_netbox_interface_template.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxInterfaceTemplate() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxInterfaceTemplateCreate,\n\t\tReadContext:   resourceNetboxInterfaceTemplateRead,\n\t\tUpdateContext: resourceNetboxInterfaceTemplateUpdate,\n\t\tDeleteContext: resourceNetboxInterfaceTemplateDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/interfacetemplate/):\n\n> A template for a network interface that will be created on all instantiations of the parent device type. See the interface documentation for more detail.`,\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 64),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"type\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"mgmt_only\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"device_type_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"device_type_id\", \"module_type_id\"},\n\t\t\t\tForceNew:     true,\n\t\t\t},\n\t\t\t\"module_type_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"device_type_id\", \"module_type_id\"},\n\t\t\t\tForceNew:     true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxInterfaceTemplateCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tlabel := d.Get(\"label\").(string)\n\tinterfaceType := d.Get(\"type\").(string)\n\tmgmtOnly := d.Get(\"mgmt_only\").(bool)\n\n\tdata := models.WritableInterfaceTemplate{\n\t\tName:        &name,\n\t\tDescription: description,\n\t\tLabel:       label,\n\t\tType:        &interfaceType,\n\t\tMgmtOnly:    mgmtOnly,\n\t}\n\n\tif deviceTypeID, ok := d.Get(\"device_type_id\").(int); ok && deviceTypeID != 0 {\n\t\tdata.DeviceType = int64ToPtr(int64(deviceTypeID))\n\t}\n\tif moduleTypeID, ok := d.Get(\"module_type_id\").(int); ok && moduleTypeID != 0 {\n\t\tdata.ModuleType = int64ToPtr(int64(moduleTypeID))\n\t}\n\tparams := dcim.NewDcimInterfaceTemplatesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimInterfaceTemplatesCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn diags\n}\n\nfunc resourceNetboxInterfaceTemplateRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tvar diags diag.Diagnostics\n\n\tparams := dcim.NewDcimInterfaceTemplatesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimInterfaceTemplatesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimInterfaceTemplatesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\ttmpl := res.GetPayload()\n\n\td.Set(\"name\", tmpl.Name)\n\td.Set(\"description\", tmpl.Description)\n\td.Set(\"label\", tmpl.Label)\n\td.Set(\"type\", tmpl.Type.Value)\n\td.Set(\"mgmt_only\", tmpl.MgmtOnly)\n\n\tif tmpl.DeviceType != nil {\n\t\td.Set(\"device_type_id\", tmpl.DeviceType.ID)\n\t}\n\tif tmpl.ModuleType != nil {\n\t\td.Set(\"module_type_id\", tmpl.ModuleType.ID)\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxInterfaceTemplateUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tlabel := d.Get(\"label\").(string)\n\tinterfaceType := d.Get(\"type\").(string)\n\tmgmtOnly := d.Get(\"mgmt_only\").(bool)\n\n\tdata := models.WritableInterfaceTemplate{\n\t\tName:        &name,\n\t\tDescription: description,\n\t\tLabel:       label,\n\t\tType:        &interfaceType,\n\t\tMgmtOnly:    mgmtOnly,\n\t}\n\n\tif d.HasChange(\"device_type_id\") {\n\t\tdeviceTypeID := int64(d.Get(\"device_type_id\").(int))\n\t\tdata.DeviceType = &deviceTypeID\n\t}\n\n\tif d.HasChange(\"module_type_id\") {\n\t\tmoduleTypeID := int64(d.Get(\"module_type_id\").(int))\n\t\tdata.ModuleType = &moduleTypeID\n\t}\n\n\tparams := dcim.NewDcimInterfaceTemplatesPartialUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Dcim.DcimInterfaceTemplatesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxInterfaceTemplateDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimInterfaceTemplatesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimInterfaceTemplatesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimInterfaceTemplatesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_interface_template_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc TestAccNetboxInterfaceTemplate_basic(t *testing.T) {\n\ttestSlug := \"interface_template\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n\tname = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n\tmodel = \"%[1]s\"\n\tslug = \"%[2]s\"\n\tpart_number = \"%[2]s\"\n\tmanufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_interface_template\" \"test\" {\n\tname = \"%[1]s\"\n\tdevice_type_id = netbox_device_type.test.id\n\ttype = \"100base-tx\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"type\", \"100base-tx\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface_template.test\", \"device_type_id\", \"netbox_device_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_interface_template.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxInterfaceTemplate_opts(t *testing.T) {\n\ttestSlug := \"interface_template\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n\tname = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n\tmodel = \"%[1]s\"\n\tslug = \"%[2]s\"\n\tpart_number = \"%[2]s\"\n\tmanufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_interface_template\" \"test\" {\n\tname = \"%[1]s\"\n\tdescription = \"%[1]s description\"\n\tlabel = \"%[1]s label\"\n\tdevice_type_id = netbox_device_type.test.id\n\ttype = \"100base-tx\"\n\tmgmt_only = true\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"description\", fmt.Sprintf(\"%s description\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"label\", fmt.Sprintf(\"%s label\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"type\", \"100base-tx\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"mgmt_only\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface_template.test\", \"device_type_id\", \"netbox_device_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n\tname = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n\tmanufacturer_id = netbox_manufacturer.test.id\n\tmodel           = \"%[1]s\"\n}\n\nresource \"netbox_interface_template\" \"test\" {\n\tname = \"%[1]s\"\n\tdescription = \"%[1]s description\"\n\tlabel = \"%[1]s label\"\n\tmodule_type_id = netbox_module_type.test.id\n\ttype = \"100base-tx\"\n\tmgmt_only = false\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"description\", fmt.Sprintf(\"%s description\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"label\", fmt.Sprintf(\"%s label\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"type\", \"100base-tx\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface_template.test\", \"mgmt_only\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface_template.test\", \"module_type_id\", \"netbox_module_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_interface_template\", &resource.Sweeper{\n\t\tName:         \"netbox_interface_template\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimInterfaceTemplatesListParams()\n\t\t\tres, err := api.Dcim.DcimInterfaceTemplatesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tmpl := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*tmpl.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimInterfaceTemplatesDeleteParams().WithID(tmpl.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimInterfaceTemplatesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted an interface template\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_interface_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxInterfaceFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n}\n\nresource \"netbox_vlan\" \"test1\" {\n  name = \"%[1]s_vlan1\"\n  vid = 1001\n  tags = []\n}\n\nresource \"netbox_vlan\" \"test2\" {\n  name = \"%[1]s_vlan2\"\n  vid = 1002\n  tags = []\n}`, testName)\n}\n\nfunc testAccNetboxInterfaceBasic(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_interface\" \"test\" {\n  name = \"%s\"\n  virtual_machine_id = netbox_virtual_machine.test.id\n  tags = [netbox_tag.test.name]\n}`, testName)\n}\n\nfunc testAccNetboxInterfaceOpts(testName string, enabled string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_interface\" \"test\" {\n  name = \"%[1]s\"\n  description = \"%[1]s\"\n  enabled = %[2]s\n  mtu = 1440\n  virtual_machine_id = netbox_virtual_machine.test.id\n}`, testName, enabled)\n}\n\nfunc testAccNetboxInterfaceVlans(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_interface\" \"test1\" {\n  name = \"%[1]s_1\"\n  mode = \"access\"\n  untagged_vlan = netbox_vlan.test1.id\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n\nresource \"netbox_interface\" \"test2\" {\n  name = \"%[1]s_2\"\n  mode = \"tagged\"\n  tagged_vlans = [netbox_vlan.test2.id]\n  untagged_vlan = netbox_vlan.test1.id\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n\nresource \"netbox_interface\" \"test3\" {\n  name = \"%[1]s_3\"\n  mode = \"tagged-all\"\n  tagged_vlans = [netbox_vlan.test1.id, netbox_vlan.test2.id]\n  virtual_machine_id = netbox_virtual_machine.test.id\n}`, testName)\n}\n\nfunc testAccNetboxInterfaceBridge(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_interface\" \"bridge\" {\n  name = \"%[1]s_1\"\n  description = \"%[1]s\"\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n\nresource \"netbox_interface\" \"test\" {\n  name = \"%[1]s_2\"\n  virtual_machine_id = netbox_virtual_machine.test.id\n  bridge_interface_id = netbox_interface.bridge.id\n}`, testName)\n}\n\nfunc TestAccNetboxInterface_basic(t *testing.T) {\n\ttestSlug := \"iface_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxInterfaceFullDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckInterfaceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxInterfaceBasic(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface.test\", \"virtual_machine_id\", \"netbox_virtual_machine.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_interface.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxInterface_opts(t *testing.T) {\n\ttestSlug := \"iface\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxInterfaceFullDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckInterfaceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxInterfaceOpts(testName, \"true\"),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"description\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"enabled\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"mtu\", \"1440\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface.test\", \"virtual_machine_id\", \"netbox_virtual_machine.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxInterfaceOpts(testName, \"false\"),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"description\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"enabled\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"mtu\", \"1440\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface.test\", \"virtual_machine_id\", \"netbox_virtual_machine.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_interface.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxInterface_vlans(t *testing.T) {\n\ttestSlug := \"iface_vlan\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxInterfaceFullDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckInterfaceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxInterfaceVlans(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test1\", \"mode\", \"access\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test2\", \"mode\", \"tagged\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test3\", \"mode\", \"tagged-all\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface.test1\", \"untagged_vlan\", \"netbox_vlan.test1\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface.test2\", \"untagged_vlan\", \"netbox_vlan.test1\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface.test2\", \"tagged_vlans.0\", \"netbox_vlan.test2\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test3\", \"tagged_vlans.#\", \"2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_interface.test1\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_interface.test2\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_interface.test3\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxInterface_bridge(t *testing.T) {\n\ttestSlug := \"iface_bridge\"\n\ttestName := testAccGetTestName(testSlug)\n\tsetUp := testAccNetboxInterfaceFullDependencies(testName)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckInterfaceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxInterfaceBridge(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_interface.test\", \"bridge_interface_id\", \"netbox_interface.bridge\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: setUp + testAccNetboxInterfaceBasic(testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_interface.test\", \"bridge_interface_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_interface.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckInterfaceDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each interface\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_interface\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our interface by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := virtualization.NewVirtualizationInterfacesReadParams().WithID(stateID)\n\t\t_, err := conn.Virtualization.VirtualizationInterfacesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"interface (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*virtualization.VirtualizationInterfacesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_interface\", &resource.Sweeper{\n\t\tName:         \"netbox_interface\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := virtualization.NewVirtualizationInterfacesListParams()\n\t\t\tres, err := api.Virtualization.VirtualizationInterfacesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, intrface := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*intrface.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := virtualization.NewVirtualizationInterfacesDeleteParams().WithID(intrface.ID)\n\t\t\t\t\t_, err := api.Virtualization.VirtualizationInterfacesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted an interface\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_inventory_item.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxInventoryItem() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxInventoryItemCreate,\n\t\tRead:   resourceNetboxInventoryItemRead,\n\t\tUpdate: resourceNetboxInventoryItemUpdate,\n\t\tDelete: resourceNetboxInventoryItemDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/inventoryitem/):\n\n> Inventory items represent hardware components installed within a device, such as a power supply or CPU or line card. They are intended to be used primarily for inventory purposes.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"label\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"manufacturer_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"part_id\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"serial\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"asset_tag\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"discovered\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  false,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"component_type\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\n\t\t\t\t\t\"dcim.powerport\",\n\t\t\t\t\t\"dcim.poweroutlet\",\n\t\t\t\t\t\"dcim.frontport\",\n\t\t\t\t\t\"dcim.rearport\",\n\t\t\t\t\t\"dcim.consoleserverport\",\n\t\t\t\t\t\"dcim.consoleport\",\n\t\t\t\t\t\"dcim.interface\",\n\t\t\t\t}, false),\n\t\t\t},\n\t\t\t\"component_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"component_type\"},\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxInventoryItemCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableInventoryItem{\n\t\tDevice:       int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:         strToPtr(d.Get(\"name\").(string)),\n\t\tParent:       getOptionalInt(d, \"parent_id\"),\n\t\tLabel:        getOptionalStr(d, \"label\", false),\n\t\tRole:         getOptionalInt(d, \"role_id\"),\n\t\tManufacturer: getOptionalInt(d, \"manufacturer_id\"),\n\t\tPartID:       getOptionalStr(d, \"part_id\", false),\n\t\tSerial:       getOptionalStr(d, \"serial\", false),\n\t\tDiscovered:   d.Get(\"discovered\").(bool),\n\t\tDescription:  getOptionalStr(d, \"description\", false),\n\t}\n\n\tif assetTag := getOptionalStr(d, \"asset_tag\", false); assetTag != \"\" {\n\t\tdata.AssetTag = &assetTag\n\t}\n\n\tif componentType := getOptionalStr(d, \"component_type\", false); componentType != \"\" {\n\t\tdata.ComponentType = &componentType\n\t\tdata.ComponentID = getOptionalInt(d, \"component_id\")\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimInventoryItemsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimInventoryItemsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxInventoryItemRead(d, m)\n}\n\nfunc resourceNetboxInventoryItemRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimInventoryItemsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimInventoryItemsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimInventoryItemsReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\titem := res.GetPayload()\n\n\tif item.Device != nil {\n\t\td.Set(\"device_id\", item.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\td.Set(\"name\", item.Name)\n\n\td.Set(\"parent_id\", item.Parent)\n\n\td.Set(\"label\", item.Label)\n\n\tif item.Role != nil {\n\t\td.Set(\"role_id\", item.Role.ID)\n\t} else {\n\t\td.Set(\"role_id\", nil)\n\t}\n\n\tif item.Manufacturer != nil {\n\t\td.Set(\"manufacturer_id\", item.Manufacturer.ID)\n\t} else {\n\t\td.Set(\"manufacturer_id\", nil)\n\t}\n\n\td.Set(\"part_id\", item.PartID)\n\td.Set(\"serial\", item.Serial)\n\td.Set(\"asset_tag\", item.AssetTag)\n\td.Set(\"discovered\", item.Discovered)\n\td.Set(\"description\", item.Description)\n\td.Set(\"component_type\", item.ComponentType)\n\td.Set(\"component_id\", item.ComponentID)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxInventoryItemUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableInventoryItem{\n\t\tDevice:       int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tName:         strToPtr(d.Get(\"name\").(string)),\n\t\tParent:       getOptionalInt(d, \"parent_id\"),\n\t\tLabel:        getOptionalStr(d, \"label\", true),\n\t\tRole:         getOptionalInt(d, \"role_id\"),\n\t\tManufacturer: getOptionalInt(d, \"manufacturer_id\"),\n\t\tPartID:       getOptionalStr(d, \"part_id\", true),\n\t\tSerial:       getOptionalStr(d, \"serial\", true),\n\t\tDiscovered:   d.Get(\"discovered\").(bool),\n\t\tDescription:  getOptionalStr(d, \"description\", true),\n\t}\n\n\tif assetTag := getOptionalStr(d, \"asset_tag\", false); assetTag != \"\" {\n\t\tdata.AssetTag = &assetTag\n\t}\n\n\tif componentType := getOptionalStr(d, \"component_type\", false); componentType != \"\" {\n\t\tdata.ComponentType = &componentType\n\t\tdata.ComponentID = getOptionalInt(d, \"component_id\")\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimInventoryItemsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimInventoryItemsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxInventoryItemRead(d, m)\n}\n\nfunc resourceNetboxInventoryItemDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimInventoryItemsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimInventoryItemsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_inventory_item_role.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxInventoryItemRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxInventoryItemRoleCreate,\n\t\tRead:   resourceNetboxInventoryItemRoleRead,\n\t\tUpdate: resourceNetboxInventoryItemRoleUpdate,\n\t\tDelete: resourceNetboxInventoryItemRoleDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/inventoryitemrole/):\n\n> Inventory items can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for power supplies, fans, interface optics, etc.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxInventoryItemRoleCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.InventoryItemRole{\n\t\tName:        strToPtr(d.Get(\"name\").(string)),\n\t\tSlug:        strToPtr(d.Get(\"slug\").(string)),\n\t\tDescription: getOptionalStr(d, \"description\", false),\n\t\tColor:       getOptionalStr(d, \"color_hex\", false),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimInventoryItemRolesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimInventoryItemRolesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxInventoryItemRoleRead(d, m)\n}\n\nfunc resourceNetboxInventoryItemRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimInventoryItemRolesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimInventoryItemRolesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimInventoryItemRolesReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\trole := res.GetPayload()\n\td.Set(\"name\", role.Name)\n\td.Set(\"slug\", role.Slug)\n\td.Set(\"color_hex\", role.Color)\n\td.Set(\"description\", role.Description)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxInventoryItemRoleUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.InventoryItemRole{\n\t\tName:        strToPtr(d.Get(\"name\").(string)),\n\t\tSlug:        strToPtr(d.Get(\"slug\").(string)),\n\t\tDescription: getOptionalStr(d, \"description\", true),\n\t\tColor:       getOptionalStr(d, \"color_hex\", false),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimInventoryItemRolesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimInventoryItemRolesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxInventoryItemRoleRead(d, m)\n}\n\nfunc resourceNetboxInventoryItemRoleDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimInventoryItemRolesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimInventoryItemRolesDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_inventory_item_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxInventoryItemRoleFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxInventoryItemRole_basic(t *testing.T) {\n\ttestSlug := \"inventory_item_role_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckInventoryItemRoleDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxInventoryItemRoleFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_inventory_item_role\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[1]s_slug\"\n\tcolor_hex = \"123456\"\n\n  description = \"%[1]s_description\"\n  tags = [ netbox_tag.test.name ]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"slug\", testName+\"_slug\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"color_hex\", \"123456\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxInventoryItemRoleFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_inventory_item_role\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[1]s_slug\"\n\tcolor_hex = \"123456\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"slug\", testName+\"_slug\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"color_hex\", \"123456\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item_role.test\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_inventory_item_role.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckInventoryItemRoleDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each inventory item role\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_inventory_item_role\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimInventoryItemRolesReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimInventoryItemRolesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"inventory item role (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimInventoryItemRolesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_inventory_item_role\", &resource.Sweeper{\n\t\tName:         \"netbox_inventory_item_role\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimInventoryItemRolesListParams()\n\t\t\tres, err := api.Dcim.DcimInventoryItemRolesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, role := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*role.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimInventoryItemRolesDeleteParams().WithID(role.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimInventoryItemRolesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted an inventory item role\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_inventory_item_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxInventoryItemFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  device_type_id = netbox_device_type.test.id\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}\n\nresource \"netbox_module\" \"test\" {\n  device_id = netbox_device.test.id\n  module_bay_id = netbox_device_module_bay.test.id\n  module_type_id = netbox_module_type.test.id\n  status = \"active\"\n}\n\nresource \"netbox_device_rear_port\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n  type = \"8p8c\"\n  positions = 1\n  mark_connected = true\n}\n\nresource \"netbox_inventory_item_role\" \"test\" {\n\tname = \"%[1]s\"\n  slug = \"%[1]s_slug\"\n\tcolor_hex = \"123456\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxInventoryItem_basic(t *testing.T) {\n\ttestSlug := \"inventory_item_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckInventoryItemDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxInventoryItemFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_inventory_item\" \"parent\" {\n\tdevice_id = netbox_device.test.id\n\tname = \"%[1]s_parent\"\n}\n\nresource \"netbox_inventory_item\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n\n\tparent_id = netbox_inventory_item.parent.id\n  label = \"%[1]s_label\"\n\trole_id = netbox_inventory_item_role.test.id\n\tmanufacturer_id = netbox_manufacturer.test.id\n\tpart_id = \"%[1]s_part\"\n\tserial = \"%[1]s_serial\"\n\tasset_tag = \"%[1]s_asset\"\n\tdiscovered = true\n\tdescription = \"%[1]s_description\"\n\tcomponent_type = \"dcim.rearport\"\n\tcomponent_id = netbox_device_rear_port.test.id\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.parent\", \"name\", testName+\"_parent\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_inventory_item.parent\", \"device_id\", \"netbox_device.test\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"label\", testName+\"_label\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"part_id\", testName+\"_part\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"serial\", testName+\"_serial\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"asset_tag\", testName+\"_asset\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"discovered\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"component_type\", \"dcim.rearport\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_inventory_item.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_inventory_item.test\", \"parent_id\", \"netbox_inventory_item.parent\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_inventory_item.test\", \"role_id\", \"netbox_inventory_item_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_inventory_item.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_inventory_item.test\", \"component_id\", \"netbox_device_rear_port.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxInventoryItemFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_inventory_item\" \"parent\" {\n\tdevice_id = netbox_device.test.id\n\tname = \"%[1]s_parent\"\n}\n\nresource \"netbox_inventory_item\" \"test\" {\n  device_id = netbox_device.test.id\n  name = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"label\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"part_id\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"serial\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"asset_tag\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"discovered\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"component_type\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"parent_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"role_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"manufacturer_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_inventory_item.test\", \"component_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_inventory_item.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_inventory_item.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckInventoryItemDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each inventory item\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_inventory_item\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimInventoryItemsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimInventoryItemsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"inventory_item (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimInventoryItemsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_inventory_item\", &resource.Sweeper{\n\t\tName:         \"netbox_inventory_item\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimInventoryItemsListParams()\n\t\t\tres, err := api.Dcim.DcimInventoryItemsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, rearPort := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*rearPort.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimInventoryItemsDeleteParams().WithID(rearPort.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimInventoryItemsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted an inventory_item\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_ip_address.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxIPAddressObjectTypeOptions = []string{\"virtualization.vminterface\", \"dcim.interface\"}\nvar resourceNetboxIPAddressStatusOptions = []string{\"active\", \"reserved\", \"deprecated\", \"dhcp\", \"slaac\"}\nvar resourceNetboxIPAddressRoleOptions = []string{\"loopback\", \"secondary\", \"anycast\", \"vip\", \"vrrp\", \"hsrp\", \"glbp\", \"carp\"}\n\nfunc resourceNetboxIPAddress() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxIPAddressCreate,\n\t\tRead:   resourceNetboxIPAddressRead,\n\t\tUpdate: resourceNetboxIPAddressUpdate,\n\t\tDelete: resourceNetboxIPAddressDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#ip-addresses):\n\n> An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.\n>\n> Like a prefix, an IP address can optionally be assigned to a VRF (otherwise, it will appear in the \"global\" table). IP addresses are automatically arranged under parent prefixes within their respective VRFs according to the IP hierarchy.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"ip_address\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.IsCIDR,\n\t\t\t},\n\t\t\t\"interface_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"object_type\"},\n\t\t\t},\n\t\t\t\"object_type\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxIPAddressObjectTypeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxIPAddressObjectTypeOptions),\n\t\t\t\tRequiredWith: []string{\"interface_id\"},\n\t\t\t},\n\t\t\t\"virtual_machine_interface_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"interface_id\", \"device_interface_id\"},\n\t\t\t},\n\t\t\t\"device_interface_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"interface_id\", \"virtual_machine_interface_id\"},\n\t\t\t},\n\t\t\t\"vrf_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxIPAddressStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxIPAddressStatusOptions),\n\t\t\t},\n\t\t\t\"dns_name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\t// NetBox always converts DNS names to lowercase\n\t\t\t\tDiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {\n\t\t\t\t\treturn strings.EqualFold(old, new)\n\t\t\t\t},\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxIPAddressRoleOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxIPAddressRoleOptions),\n\t\t\t},\n\t\t\t\"nat_inside_address_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"nat_outside_addresses\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tComputed: true,\n\t\t\t\tElem: &schema.Resource{\n\t\t\t\t\tSchema: map[string]*schema.Schema{\n\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"ip_address\": {\n\t\t\t\t\t\t\tType:     schema.TypeString,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"address_family\": {\n\t\t\t\t\t\t\tType:     schema.TypeInt,\n\t\t\t\t\t\t\tComputed: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxIPAddressCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableIPAddress{}\n\n\tdata.Address = strToPtr(d.Get(\"ip_address\").(string))\n\tdata.Status = d.Get(\"status\").(string)\n\n\tdata.Description = getOptionalStr(d, \"description\", false)\n\tdata.Role = getOptionalStr(d, \"role\", false)\n\tdata.DNSName = getOptionalStr(d, \"dns_name\", false)\n\tdata.Vrf = getOptionalInt(d, \"vrf_id\")\n\tdata.Tenant = getOptionalInt(d, \"tenant_id\")\n\tdata.NatInside = getOptionalInt(d, \"nat_inside_address_id\")\n\n\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\tinterfaceID := getOptionalInt(d, \"interface_id\")\n\n\tswitch {\n\tcase vmInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"virtualization.vminterface\")\n\t\tdata.AssignedObjectID = vmInterfaceID\n\tcase deviceInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"dcim.interface\")\n\t\tdata.AssignedObjectID = deviceInterfaceID\n\t// if interfaceID is given, object_type must be set as well\n\tcase interfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(d.Get(\"object_type\").(string))\n\t\tdata.AssignedObjectID = interfaceID\n\t// default = ip is not linked to anything\n\tdefault:\n\t\tdata.AssignedObjectType = strToPtr(\"\")\n\t\tdata.AssignedObjectID = nil\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := ipam.NewIpamIPAddressesCreateParams().WithData(&data)\n\n\tres, err := api.Ipam.IpamIPAddressesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxIPAddressRead(d, m)\n}\n\nfunc resourceNetboxIPAddressRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamIPAddressesReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamIPAddressesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamIPAddressesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tipAddress := res.GetPayload()\n\tif ipAddress.AssignedObjectID != nil {\n\t\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\t\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\t\tinterfaceID := getOptionalInt(d, \"interface_id\")\n\n\t\tswitch {\n\t\tcase vmInterfaceID != nil:\n\t\t\td.Set(\"virtual_machine_interface_id\", ipAddress.AssignedObjectID)\n\t\t\td.Set(\"interface_id\", nil)\n\t\t\td.Set(\"object_type\", \"\")\n\t\tcase deviceInterfaceID != nil:\n\t\t\td.Set(\"device_interface_id\", ipAddress.AssignedObjectID)\n\t\t\td.Set(\"interface_id\", nil)\n\t\t\td.Set(\"object_type\", \"\")\n\t\t// if interfaceID is given, object_type must be set as well\n\t\tcase interfaceID != nil:\n\t\t\td.Set(\"interface_id\", ipAddress.AssignedObjectID)\n\t\t\td.Set(\"object_type\", ipAddress.AssignedObjectType)\n\t\tdefault:\n\t\t\t// Set changes made to the ip address outside of Terraform and update the state accordingly.\n\t\t\td.Set(\"interface_id\", ipAddress.AssignedObjectID)\n\t\t\td.Set(\"object_type\", ipAddress.AssignedObjectType)\n\t\t}\n\t} else {\n\t\td.Set(\"virtual_machine_interface_id\", nil)\n\t\td.Set(\"device_interface_id\", nil)\n\t\td.Set(\"interface_id\", nil)\n\t\td.Set(\"object_type\", \"\")\n\t}\n\n\tif ipAddress.Vrf != nil {\n\t\td.Set(\"vrf_id\", ipAddress.Vrf.ID)\n\t} else {\n\t\td.Set(\"vrf_id\", nil)\n\t}\n\n\tif ipAddress.Tenant != nil {\n\t\td.Set(\"tenant_id\", ipAddress.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tif ipAddress.DNSName != \"\" {\n\t\td.Set(\"dns_name\", ipAddress.DNSName)\n\t}\n\n\tif ipAddress.Role != nil {\n\t\td.Set(\"role\", ipAddress.Role.Value)\n\t} else {\n\t\td.Set(\"role\", nil)\n\t}\n\n\tif ipAddress.NatInside != nil {\n\t\td.Set(\"nat_inside_address_id\", ipAddress.NatInside.ID)\n\t} else {\n\t\td.Set(\"nat_inside_address_id\", nil)\n\t}\n\n\tif ipAddress.NatOutside != nil {\n\t\tnatOutsideIPAddresses := ipAddress.NatOutside\n\n\t\tvar s []map[string]interface{}\n\t\tfor _, v := range natOutsideIPAddresses {\n\t\t\tvar mapping = make(map[string]interface{})\n\n\t\t\tmapping[\"id\"] = v.ID\n\t\t\tmapping[\"ip_address\"] = v.Address\n\t\t\tmapping[\"address_family\"] = v.Family\n\n\t\t\ts = append(s, mapping)\n\t\t}\n\t\td.Set(\"nat_outside_addresses\", s)\n\t} else {\n\t\td.Set(\"nat_outside_addresses\", nil)\n\t}\n\n\td.Set(\"ip_address\", ipAddress.Address)\n\td.Set(\"description\", ipAddress.Description)\n\td.Set(\"status\", ipAddress.Status.Value)\n\tapi.readTags(d, ipAddress.Tags)\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\treturn nil\n}\n\nfunc resourceNetboxIPAddressUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableIPAddress{}\n\n\tdata.Address = strToPtr(d.Get(\"ip_address\").(string))\n\tdata.Status = d.Get(\"status\").(string)\n\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.Role = getOptionalStr(d, \"role\", false)\n\tdata.DNSName = getOptionalStr(d, \"dns_name\", true)\n\tdata.Vrf = getOptionalInt(d, \"vrf_id\")\n\tdata.Tenant = getOptionalInt(d, \"tenant_id\")\n\tdata.NatInside = getOptionalInt(d, \"nat_inside_address_id\")\n\n\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\tinterfaceID := getOptionalInt(d, \"interface_id\")\n\n\tswitch {\n\tcase vmInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"virtualization.vminterface\")\n\t\tdata.AssignedObjectID = vmInterfaceID\n\tcase deviceInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"dcim.interface\")\n\t\tdata.AssignedObjectID = deviceInterfaceID\n\t// if interfaceID is given, object_type must be set as well\n\tcase interfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(d.Get(\"object_type\").(string))\n\t\tdata.AssignedObjectID = interfaceID\n\t// default = ip is not linked to anything\n\tdefault:\n\t\tdata.AssignedObjectType = strToPtr(\"\")\n\t\tdata.AssignedObjectID = nil\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := ipam.NewIpamIPAddressesUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Ipam.IpamIPAddressesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxIPAddressRead(d, m)\n}\n\nfunc resourceNetboxIPAddressDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamIPAddressesDeleteParams().WithID(id)\n\n\t_, err := api.Ipam.IpamIPAddressesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamIPAddressesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_ip_address_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxIPAddressFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_vrf\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n}\n\nresource \"netbox_interface\" \"test\" {\n  name = \"%[1]s\"\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n`, testName)\n}\n\nfunc testAccNetboxIPAddressFullDeviceDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  role_id = netbox_device_role.test.id\n}\nresource \"netbox_device_interface\" \"test\" {\n  name = \"%[1]s\"\n  device_id = netbox_device.test.id\n  type = \"1000base-t\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxIPAddress_basic(t *testing.T) {\n\ttestIP := \"1.1.1.1/32\"\n\ttestSlug := \"ipaddress\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  interface_id = netbox_interface.test.id\n  object_type = \"virtualization.vminterface\"\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"object_type\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"tenant_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"vrf_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  interface_id = netbox_interface.test.id\n  object_type = \"virtualization.vminterface\"\n  status = \"reserved\"\n  tenant_id = netbox_tenant.test.id\n  vrf_id = netbox_vrf.test.id\n  tags = [netbox_tag.test.name]\n  description = \"description for %[1]s\"\n  role = \"loopback\"\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"reserved\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"object_type\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"vrf_id\", \"netbox_vrf.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"description\", fmt.Sprintf(\"description for %[1]s\", testIP)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"role\", \"loopback\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  interface_id = netbox_interface.test.id\n  object_type = \"virtualization.vminterface\"\n  status = \"dhcp\"\n  tags = [netbox_tag.test.name]\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"dhcp\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"object_type\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"tenant_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"vrf_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"role\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  interface_id = netbox_interface.test.id\n  object_type = \"virtualization.vminterface\"\n  status = \"provoke_error\"\n  tags = [netbox_tag.test.name]\n}`, testIP),\n\t\t\t\tExpectError: regexp.MustCompile(\"expected status to be one of .*\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  interface_id = netbox_interface.test.id\n  object_type = \"virtualization.vminterface\"\n  status = \"deprecated\"\n  tags = [netbox_tag.test.name]\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"deprecated\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"object_type\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  interface_id = netbox_interface.test.id\n  object_type = \"virtualization.vminterface\"\n  status = \"active\"\n  dns_name = \"mytest.example.com\"\n  tags = [netbox_tag.test.name]\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"object_type\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"dns_name\", \"mytest.example.com\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_ip_address.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"interface_id\", \"object_type\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIPAddress_cf(t *testing.T) {\n\ttestIP := \"1.1.1.8/32\"\n\ttestSlug := \"ipaddr_cf\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name   = \"%s\"\n  type   = \"text\"\n  weight = 100\n  content_types = [\"ipam.ipaddress\"]\n}\nresource \"netbox_ip_address\" \"test_customfield\" {\n  ip_address = \"%s\"\n  status = \"active\"\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"test-field\"\n  }\n}`, testSlug, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test_customfield\", fmt.Sprintf(\"custom_fields.%s\", testSlug), \"test-field\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ip_address.test_customfield\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIPAddress_deviceByObjectType(t *testing.T) {\n\ttestIP := \"1.1.1.2/32\"\n\ttestSlug := \"ipadr_dev_ot\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDeviceDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  object_type = \"dcim.interface\"\n  interface_id = netbox_device_interface.test.id\n  status = \"active\"\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"object_type\", \"dcim.interface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"interface_id\", \"netbox_device_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_ip_address.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"interface_id\", \"object_type\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIPAddress_vmByObjectType(t *testing.T) {\n\ttestIP := \"1.1.1.3/32\"\n\ttestSlug := \"ipadr_vm_ot\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  object_type = \"virtualization.vminterface\"\n  interface_id = netbox_interface.test.id\n  status = \"active\"\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"object_type\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_ip_address.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"interface_id\", \"object_type\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIPAddress_vmSwitchStyle(t *testing.T) {\n\ttestIP := \"1.1.1.9/32\"\n\ttestSlug := \"ipadr_vm_sw\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  object_type = \"virtualization.vminterface\"\n  interface_id = netbox_interface.test.id\n  status = \"active\"\n}`, testIP),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n}`, testIP),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_ip_address.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"interface_id\", \"object_type\", \"virtual_machine_interface_id\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxIPAddress_deviceByFieldName tests if creating an ip address and linking it to a device via the `device_interface_id` field works\nfunc TestAccNetboxIPAddress_deviceByFieldName(t *testing.T) {\n\ttestIP := \"1.1.1.4/32\"\n\ttestSlug := \"ipadr_dev_fn\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDeviceDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  device_interface_id = netbox_device_interface.test.id\n  status = \"active\"\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"device_interface_id\", \"netbox_device_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ip_address.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t\t// import step doesn't have context about device_interface_id, thus we\n\t\t\t\t// get interface_id and object_type imported instead\n\t\t\t\tImportStateVerifyIgnore: []string{\"interface_id\", \"object_type\", \"device_interface_id\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIPAddress_vmByFieldName(t *testing.T) {\n\ttestIP := \"1.1.1.5/32\"\n\ttestSlug := \"ipadr_vm_fn\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  status = \"active\"\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"virtual_machine_interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ip_address.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t\t// import step doesn't have context about virtual_machine_interface_id, thus we\n\t\t\t\t// get interface_id and object_type imported instead\n\t\t\t\tImportStateVerifyIgnore: []string{\"interface_id\", \"object_type\", \"virtual_machine_interface_id\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxIPAddress_standalone tests the case where an ip address is not linked to a vm or device\nfunc TestAccNetboxIPAddress_standalone(t *testing.T) {\n\ttestIP := \"1.1.1.6/32\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  status = \"active\"\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ip_address.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIPAddress_nat(t *testing.T) {\n\ttestIP := \"1.1.1.10/32\"\n\ttestIPInside := \"1.1.1.11/32\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  status = \"active\"\n}\n\nresource \"netbox_ip_address\" \"inside\" {\n  ip_address = \"%s\"\n  status = \"active\"\n  nat_inside_address_id = netbox_ip_address.test.id\n}\n`, testIP, testIPInside),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"ip_address\", testIP),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.inside\", \"nat_inside_address_id\", \"netbox_ip_address.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// we have to make another step because netbox_ip_address.test.nat_outside_addresses needs a refresh\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  status = \"active\"\n}\n\nresource \"netbox_ip_address\" \"inside\" {\n  ip_address = \"%s\"\n  status = \"active\"\n  nat_inside_address_id = netbox_ip_address.test.id\n}\n`, testIP, testIPInside),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"nat_outside_addresses.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_address.test\", \"nat_outside_addresses.0.id\", \"netbox_ip_address.inside\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ip_address.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIPAddress_invalidConfig(t *testing.T) {\n\ttestIP := \"1.1.1.7/32\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  object_type = \"dcim.interface\"\n  status = \"active\"\n}`, testIP),\n\t\t\t\tExpectError: regexp.MustCompile(\".*all of `interface_id,object_type` must be specified.*\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  interface_id = 1\n  status = \"active\"\n}`, testIP),\n\t\t\t\tExpectError: regexp.MustCompile(\".*all of `interface_id,object_type` must be specified.*\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  virtual_machine_interface_id = 1\n  interface_id = 1\n  object_type = \"dcim.interface\"\n  status = \"active\"\n}`, testIP),\n\t\t\t\tExpectError: regexp.MustCompile(\".*conflicts with interface_id.*\"),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_ip_address\", &resource.Sweeper{\n\t\tName:         \"netbox_ip_address\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamIPAddressesListParams()\n\t\t\tres, err := api.Ipam.IpamIPAddressesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, ipAddress := range res.GetPayload().Results {\n\t\t\t\tif len(ipAddress.Tags) > 0 && (ipAddress.Tags[0] == &models.NestedTag{Name: strToPtr(\"acctest\"), Slug: strToPtr(\"acctest\")}) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamIPAddressesDeleteParams().WithID(ipAddress.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamIPAddressesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted an ip address\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIPAddress_dnsNameCase(t *testing.T) {\n\ttestIP := \"1.1.1.253/32\"\n\ttestSlug := \"ipaddr_dns_case\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\t// Mixed-case dns_name: NetBox stores it as lowercase.\n\t\t\t\t// Without DiffSuppressFunc the post-apply plan check detects\n\t\t\t\t// drift and fails with \"the plan was not empty\" (#828).\n\t\t\t\tConfig: testAccNetboxIPAddressFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_ip_address\" \"test\" {\n  ip_address = \"%s\"\n  status     = \"active\"\n  dns_name   = \"Mytest.Example.Com\"\n}`, testIP),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_address.test\", \"dns_name\", \"mytest.example.com\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_ip_range.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxIPRangeStatusOptions = []string{\"active\", \"reserved\", \"deprecated\"}\n\nfunc resourceNetboxIPRange() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxIPRangeCreate,\n\t\tRead:   resourceNetboxIPRangeRead,\n\t\tUpdate: resourceNetboxIPRangeUpdate,\n\t\tDelete: resourceNetboxIPRangeDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#ip-ranges):\n\n> This model represents an arbitrary range of individual IPv4 or IPv6 addresses, inclusive of its starting and ending addresses. For instance, the range 192.0.2.10 to 192.0.2.20 has eleven members. (The total member count is available as the size property on an IPRange instance.) Like prefixes and IP addresses, each IP range may optionally be assigned to a VRF and/or tenant.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"start_address\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"end_address\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tDefault:      \"active\",\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxIPRangeStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxIPRangeStatusOptions),\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"vrf_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"size\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tComputed:    true,\n\t\t\t\tDescription: \"The total member count of the IP range\",\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxIPRangeCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableIPRange{}\n\n\tstartAddress := d.Get(\"start_address\").(string)\n\tendAddress := d.Get(\"end_address\").(string)\n\tstatus := d.Get(\"status\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.StartAddress = &startAddress\n\tdata.EndAddress = &endAddress\n\tdata.Status = status\n\tdata.Description = description\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamIPRangesCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamIPRangesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxIPRangeUpdate(d, m)\n}\n\nfunc resourceNetboxIPRangeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamIPRangesReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamIPRangesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamIPRangesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tif res.GetPayload().StartAddress != nil {\n\t\td.Set(\"start_address\", res.GetPayload().StartAddress)\n\t}\n\n\tif res.GetPayload().EndAddress != nil {\n\t\td.Set(\"end_address\", res.GetPayload().EndAddress)\n\t}\n\n\tif res.GetPayload().Status != nil {\n\t\td.Set(\"status\", res.GetPayload().Status.Value)\n\t}\n\n\tif res.GetPayload().Vrf != nil {\n\t\td.Set(\"vrf_id\", res.GetPayload().Vrf.ID)\n\t}\n\n\tif res.GetPayload().Description != \"\" {\n\t\td.Set(\"description\", res.GetPayload().Description)\n\t}\n\n\tif res.GetPayload().Tenant != nil {\n\t\td.Set(\"tenant_id\", res.GetPayload().Tenant.ID)\n\t}\n\n\tif res.GetPayload().Role != nil {\n\t\td.Set(\"role_id\", res.GetPayload().Role.ID)\n\t}\n\n\tif res.GetPayload().Size != 0 {\n\t\td.Set(\"size\", res.GetPayload().Size)\n\t}\n\n\tapi.readTags(d, res.GetPayload().Tags)\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxIPRangeUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableIPRange{}\n\tstartAddress := d.Get(\"start_address\").(string)\n\tendAddress := d.Get(\"end_address\").(string)\n\tstatus := d.Get(\"status\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.StartAddress = &startAddress\n\tdata.EndAddress = &endAddress\n\n\tdata.Status = status\n\tdata.Description = description\n\n\tif vrfID, ok := d.GetOk(\"vrf_id\"); ok {\n\t\tdata.Vrf = int64ToPtr(int64(vrfID.(int)))\n\t}\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\n\tif roleID, ok := d.GetOk(\"role_id\"); ok {\n\t\tdata.Role = int64ToPtr(int64(roleID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := ipam.NewIpamIPRangesUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Ipam.IpamIPRangesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxIPRangeRead(d, m)\n}\n\nfunc resourceNetboxIPRangeDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamIPRangesDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamIPRangesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamIPRangesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_ip_range_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxIPRangeFullDependencies(testStartAddress string, testSlug string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_vrf\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_ipam_role\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n`, testStartAddress, testSlug)\n}\nfunc TestAccNetboxIpRange_basic(t *testing.T) {\n\ttestSlug := \"range_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\ttestStartAddress := \"10.0.0.1/24\"\n\ttestEndAddress := \"10.0.0.50/24\"\n\ttestDescription := \"Test Description\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPRangeFullDependencies(testName, randomSlug) + fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test_basic\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n  status = \"active\"\n  description = \"%s\"\n  tags = []\n}`, testStartAddress, testEndAddress, testDescription),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"start_address\", testStartAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"end_address\", testEndAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"description\", testDescription),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"size\", \"50\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPRangeFullDependencies(testName, randomSlug) + fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test_basic\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n  vrf_id = netbox_vrf.test.id\n  tenant_id = netbox_tenant.test.id\n  status = \"active\"\n  description = \"%s\"\n  tags = []\n}`, testStartAddress, testEndAddress, testDescription),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"start_address\", testStartAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"end_address\", testEndAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"description\", testDescription),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_range.test_basic\", \"vrf_id\", \"netbox_vrf.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_range.test_basic\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_basic\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ip_range.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpRange_with_dependencies(t *testing.T) {\n\ttestSlug := \"range_with_dependencies\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\ttestStartAddress := \"10.0.0.51/24\"\n\ttestEndAddress := \"10.0.0.100/24\"\n\ttestDescription := \"Test Description\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxIPRangeFullDependencies(testName, randomSlug) + fmt.Sprintf(`\nresource \"netbox_ip_range\" \"test_with_dependencies\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n  description = \"%s\"\n  vrf_id = netbox_vrf.test.id\n  status = \"active\"\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_ipam_role.test.id\n  tags = [netbox_tag.test.name]\n}`, testStartAddress, testEndAddress, testDescription),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_with_dependencies\", \"start_address\", testStartAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_with_dependencies\", \"end_address\", testEndAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_with_dependencies\", \"description\", testDescription),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_with_dependencies\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_range.test_with_dependencies\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_range.test_with_dependencies\", \"vrf_id\", \"netbox_vrf.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_ip_range.test_with_dependencies\", \"role_id\", \"netbox_ipam_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_with_dependencies\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_with_dependencies\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_with_dependencies\", \"size\", \"50\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ip_range.test_with_dependencies\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxIpRange_cf(t *testing.T) {\n\ttestSlug := \"range_cf\"\n\ttestStartAddress := \"10.0.1.1/24\"\n\ttestEndAddress := \"10.0.1.50/24\"\n\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name   = \"%s\"\n  type   = \"text\"\n  weight = 100\n  content_types = [\"ipam.iprange\"]\n}\n\nresource \"netbox_ip_range\" \"test_cf\" {\n  start_address = \"%s\"\n  end_address = \"%s\"\n  status = \"active\"\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"test-field\"\n  }\n}`, testSlug, testStartAddress, testEndAddress),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_cf\", \"start_address\", testStartAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_cf\", \"end_address\", testEndAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ip_range.test_cf\", fmt.Sprintf(\"custom_fields.%s\", testSlug), \"test-field\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ip_range.test_cf\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_ip_range\", &resource.Sweeper{\n\t\tName:         \"netbox_ip_range\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamIPRangesListParams()\n\t\t\tres, err := api.Ipam.IpamIPRangesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, r := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*r.StartAddress, testPrefix) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamIPRangesDeleteParams().WithID(r.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamIPRangesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a range\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_ipam_role.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxIpamRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxIpamRoleCreate,\n\t\tRead:   resourceNetboxIpamRoleRead,\n\t\tUpdate: resourceNetboxIpamRoleUpdate,\n\t\tDelete: resourceNetboxIpamRoleDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#prefixvlan-roles):\n\n> A role indicates the function of a prefix or VLAN. For example, you might define Data, Voice, and Security roles. Generally, a prefix will be assigned the same functional role as the VLAN to which it is assigned (if any).`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"weight\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.IntBetween(0, 32767),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\nfunc resourceNetboxIpamRoleCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.Role{}\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\tweight := int64(d.Get(\"weight\").(int))\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Name = &name\n\tdata.Slug = &slug\n\n\tdata.Weight = &weight\n\tdata.Description = description\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := ipam.NewIpamRolesCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamRolesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxIpamRoleUpdate(d, m)\n}\n\nfunc resourceNetboxIpamRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamRolesReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamRolesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamRolesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tif res.GetPayload().Name != nil {\n\t\td.Set(\"name\", res.GetPayload().Name)\n\t}\n\n\tif res.GetPayload().Slug != nil {\n\t\td.Set(\"slug\", res.GetPayload().Slug)\n\t}\n\n\tif res.GetPayload().Weight != nil {\n\t\td.Set(\"weight\", res.GetPayload().Weight)\n\t}\n\n\tif res.GetPayload().Description != \"\" {\n\t\td.Set(\"description\", res.GetPayload().Description)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxIpamRoleUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.Role{}\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\tweight := int64(d.Get(\"weight\").(int))\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Name = &name\n\tdata.Slug = &slug\n\n\tdata.Weight = &weight\n\tdata.Description = description\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := ipam.NewIpamRolesUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Ipam.IpamRolesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxIpamRoleRead(d, m)\n}\n\nfunc resourceNetboxIpamRoleDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamRolesDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamRolesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamRolesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_ipam_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxRole_basic(t *testing.T) {\n\ttestSlug := \"role_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ipam_role\" \"test_basic\" {\n  name = \"%s\"\n  slug = \"%s\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ipam_role.test_basic\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ipam_role.test_basic\", \"slug\", randomSlug),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ipam_role.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxRole_extended(t *testing.T) {\n\ttestSlug := \"role_extended\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestWeight := \"55\"\n\ttestDescription := \"Test description\"\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_ipam_role\" \"role_extended\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  weight = \"%[3]s\"\n  description = \"%[4]s\"\n\n}`, testName, randomSlug, testWeight, testDescription),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ipam_role.role_extended\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ipam_role.role_extended\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ipam_role.role_extended\", \"weight\", testWeight),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_ipam_role.role_extended\", \"description\", testDescription),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_ipam_role.role_extended\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_ipam_role\", &resource.Sweeper{\n\t\tName:         \"netbox_ipam_role\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamRolesListParams()\n\t\t\tres, err := api.Ipam.IpamRolesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, role := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*role.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamRolesDeleteParams().WithID(role.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamRolesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a role\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_location.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxLocation() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxLocationCreate,\n\t\tRead:   resourceNetboxLocationRead,\n\t\tUpdate: resourceNetboxLocationUpdate,\n\t\tDelete: resourceNetboxLocationDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#locations):\n\n> Racks and devices can be grouped by location within a site. A location may represent a floor, room, cage, or similar organizational unit. Locations can be nested to form a hierarchy. For example, you may have floors within a site, and rooms within a floor.\n\nEach location must have a name that is unique within its parent site and location, if any.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"facility\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 50),\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxLocationCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableLocation{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.Facility = getOptionalStr(d, \"facility\", true)\n\n\tsiteIDValue, ok := d.GetOk(\"site_id\")\n\tif ok {\n\t\tdata.Site = int64ToPtr(int64(siteIDValue.(int)))\n\t}\n\n\tparentIDValue, ok := d.GetOk(\"parent_id\")\n\tif ok {\n\t\tdata.Parent = int64ToPtr(int64(parentIDValue.(int)))\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantIDValue.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimLocationsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimLocationsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxLocationRead(d, m)\n}\n\nfunc resourceNetboxLocationRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimLocationsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimLocationsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimLocationsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tlocation := res.GetPayload()\n\n\td.Set(\"name\", location.Name)\n\td.Set(\"slug\", location.Slug)\n\td.Set(\"description\", location.Description)\n\td.Set(\"facility\", location.Facility)\n\n\tif res.GetPayload().Site != nil {\n\t\td.Set(\"site_id\", res.GetPayload().Site.ID)\n\t} else {\n\t\td.Set(\"site_id\", nil)\n\t}\n\n\tif res.GetPayload().Parent != nil {\n\t\td.Set(\"parent_id\", res.GetPayload().Parent.ID)\n\t} else {\n\t\td.Set(\"parent_id\", nil)\n\t}\n\n\tif res.GetPayload().Tenant != nil {\n\t\td.Set(\"tenant_id\", res.GetPayload().Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxLocationUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableLocation{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.Facility = getOptionalStr(d, \"facility\", true)\n\n\tsiteIDValue, ok := d.GetOk(\"site_id\")\n\tif ok {\n\t\tdata.Site = int64ToPtr(int64(siteIDValue.(int)))\n\t}\n\n\tparentIDValue := d.Get(\"parent_id\")\n\tdata.Parent = int64ToPtr(int64(parentIDValue.(int)))\n\n\t// remove parent (set null) if we got zero ID\n\tif parentIDValue == 0 {\n\t\tdata.Parent = nil\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantIDValue.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := dcim.NewDcimLocationsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimLocationsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxLocationRead(d, m)\n}\n\nfunc resourceNetboxLocationDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimLocationsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimLocationsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimLocationsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_location_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxLocation_basic(t *testing.T) {\n\ttestSlug := \"location_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestNameSub := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\trandomSlugSub := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name        = \"%[1]s\"\n  slug        = \"%[2]s\"\n  description = \"my-description\"\n  facility    = \"Building B\"\n  site_id     = netbox_site.test.id\n  tenant_id   = netbox_tenant.test.id\n}\n\nresource \"netbox_location\" \"test-sub\" {\n  name        = \"%[3]s\"\n  slug        = \"%[4]s\"\n  description = \"my-description\"\n  parent_id   = netbox_location.test.id\n  site_id     = netbox_site.test.id\n}`, testName, randomSlug, testNameSub, randomSlugSub),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"description\", \"my-description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"facility\", \"Building B\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_location.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_location.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_location.test\", \"id\", \"netbox_location.test-sub\", \"parent_id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test_2\" {\n  name = \"%[1]s_b\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  site_id = netbox_site.test_2.id\n  tenant_id = netbox_tenant.test.id\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"facility\", \"\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_location.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxLocation_updateParent(t *testing.T) {\n\ttestSlug := \"loc_upd_parent\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestNameSub := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\trandomSlugSub := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxLocationUpdateParent1(testName, randomSlug, testNameSub, randomSlugSub),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"description\", \"my-description\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_location.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_location.test\", \"id\", \"netbox_location.test_sub\", \"parent_id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxLocationUpdateParent2(testName, randomSlug, testNameSub, randomSlugSub),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test\", \"description\", \"my-description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_location.test_sub\", \"parent_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccNetboxLocationUpdateParent1(testName string, randomSlug string, testNameSub string, randomSlugSub string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name        = \"%[1]s\"\n  slug        = \"%[2]s\"\n  description = \"my-description\"\n  site_id     = netbox_site.test.id\n}\n\nresource \"netbox_location\" \"test_sub\" {\n  name        = \"%[3]s\"\n  slug        = \"%[4]s\"\n  description = \"my-description\"\n  parent_id   = netbox_location.test.id\n  site_id     = netbox_site.test.id\n}`, testName, randomSlug, testNameSub, randomSlugSub)\n}\n\nfunc testAccNetboxLocationUpdateParent2(testName string, randomSlug string, testNameSub string, randomSlugSub string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name        = \"%[1]s\"\n  slug        = \"%[2]s\"\n  description = \"my-description\"\n  site_id     = netbox_site.test.id\n}\n\nresource \"netbox_location\" \"test_sub\" {\n  name        = \"%[3]s\"\n  slug        = \"%[4]s\"\n  description = \"my-description\"\n  parent_id   = \"0\"\n  site_id     = netbox_site.test.id\n}`, testName, randomSlug, testNameSub, randomSlugSub)\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_location\", &resource.Sweeper{\n\t\tName:         \"netbox_location\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimLocationsListParams()\n\t\t\tres, err := api.Dcim.DcimLocationsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, Location := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*Location.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimLocationsDeleteParams().WithID(Location.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimLocationsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a location\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_mac_address.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxMACAddressObjectTypeOptions = []string{\"virtualization.vminterface\", \"dcim.interface\"}\n\nfunc resourceNetboxMACAddress() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxMACAddressCreate,\n\t\tRead:   resourceNetboxMACAddressRead,\n\t\tUpdate: resourceNetboxMACAddressUpdate,\n\t\tDelete: resourceNetboxMACAddressDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://netboxlabs.com/docs/netbox/models/dcim/macaddress/):\n\n> A MAC address object in NetBox comprises a single Ethernet link layer address, and represents a MAC address as reported by or assigned to a network interface. MAC addresses can be assigned to device and virtual machine interfaces. A MAC address can be specified as the primary MAC address for a given device or VM interface.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"mac_address\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t\t// Netbox converts MAC addresses always to uppercase\n\t\t\t\tDiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {\n\t\t\t\t\treturn strings.EqualFold(old, new)\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"interface_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"object_type\"},\n\t\t\t},\n\t\t\t\"object_type\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxMACAddressObjectTypeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxMACAddressObjectTypeOptions),\n\t\t\t\tRequiredWith: []string{\"interface_id\"},\n\t\t\t},\n\t\t\t\"virtual_machine_interface_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"interface_id\", \"device_interface_id\"},\n\t\t\t},\n\t\t\t\"device_interface_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"interface_id\", \"virtual_machine_interface_id\"},\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxMACAddressCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.MACAddress{}\n\n\tdata.MacAddress = strToPtr(d.Get(\"mac_address\").(string))\n\n\tdata.Description = strToPtr(getOptionalStr(d, \"description\", false))\n\tdata.Comments = strToPtr(getOptionalStr(d, \"comments\", false))\n\n\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\tinterfaceID := getOptionalInt(d, \"interface_id\")\n\n\tswitch {\n\tcase vmInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"virtualization.vminterface\")\n\t\tdata.AssignedObjectID = vmInterfaceID\n\tcase deviceInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"dcim.interface\")\n\t\tdata.AssignedObjectID = deviceInterfaceID\n\t// if interfaceID is given, object_type must be set as well\n\tcase interfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(d.Get(\"object_type\").(string))\n\t\tdata.AssignedObjectID = interfaceID\n\t// default = mac address is not linked to anything\n\tdefault:\n\t\tdata.AssignedObjectType = strToPtr(\"\")\n\t\tdata.AssignedObjectID = nil\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := dcim.NewDcimMacAddressesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimMacAddressesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxMACAddressRead(d, m)\n}\n\nfunc resourceNetboxMACAddressRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimMacAddressesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimMacAddressesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimMacAddressesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tmacAddress := res.GetPayload()\n\n\tif macAddress.AssignedObjectID != nil && macAddress.AssignedObjectType != nil {\n\t\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\t\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\t\tinterfaceID := getOptionalInt(d, \"interface_id\")\n\n\t\tswitch {\n\t\tcase vmInterfaceID != nil && *macAddress.AssignedObjectType == \"virtualization.vminterface\":\n\t\t\td.Set(\"virtual_machine_interface_id\", macAddress.AssignedObjectID)\n\t\tcase deviceInterfaceID != nil && *macAddress.AssignedObjectType == \"dcim.interface\":\n\t\t\td.Set(\"device_interface_id\", macAddress.AssignedObjectID)\n\t\t// if interfaceID is given, object_type must be set as well\n\t\tcase interfaceID != nil:\n\t\t\td.Set(\"object_type\", macAddress.AssignedObjectType)\n\t\t\td.Set(\"interface_id\", macAddress.AssignedObjectID)\n\t\t}\n\t} else {\n\t\td.Set(\"interface_id\", nil)\n\t\td.Set(\"object_type\", \"\")\n\t}\n\n\td.Set(\"mac_address\", macAddress.MacAddress)\n\td.Set(\"description\", macAddress.Description)\n\td.Set(\"comments\", macAddress.Comments)\n\tapi.readTags(d, macAddress.Tags)\n\n\tcf := getCustomFields(macAddress.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxMACAddressUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.MACAddress{}\n\n\tdata.MacAddress = strToPtr(d.Get(\"mac_address\").(string))\n\n\tdata.Description = strToPtr(getOptionalStr(d, \"description\", false))\n\tdata.Comments = strToPtr(getOptionalStr(d, \"comments\", false))\n\n\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\tinterfaceID := getOptionalInt(d, \"interface_id\")\n\n\tswitch {\n\tcase vmInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"virtualization.vminterface\")\n\t\tdata.AssignedObjectID = vmInterfaceID\n\tcase deviceInterfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(\"dcim.interface\")\n\t\tdata.AssignedObjectID = deviceInterfaceID\n\t// if interfaceID is given, object_type must be set as well\n\tcase interfaceID != nil:\n\t\tdata.AssignedObjectType = strToPtr(d.Get(\"object_type\").(string))\n\t\tdata.AssignedObjectID = interfaceID\n\t// default = mac address is not linked to anything\n\tdefault:\n\t\tdata.AssignedObjectType = strToPtr(\"\")\n\t\tdata.AssignedObjectID = nil\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := dcim.NewDcimMacAddressesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimMacAddressesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxMACAddressRead(d, m)\n}\n\nfunc resourceNetboxMACAddressDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimMacAddressesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimMacAddressesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimMacAddressesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_mac_address_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxMACAddressFullVmDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_vrf\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n}\n\nresource \"netbox_interface\" \"test\" {\n  name = \"%[1]s\"\n  virtual_machine_id = netbox_virtual_machine.test.id\n}`, testName)\n}\n\nfunc testAccNetboxMACAddressFullDeviceDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  role_id = netbox_device_role.test.id\n}\n\nresource \"netbox_device_interface\" \"test\" {\n  name = \"%[1]s\"\n  device_id = netbox_device.test.id\n  type = \"1000base-t\"\n}`, testName)\n}\n\nfunc TestAccNetboxMACAddress_standalone(t *testing.T) {\n\ttestSlug := \"mac-addr\"\n\tmacAddress := \"00:1A:2B:3C:4D:5E\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_mac_address\" \"test\" {\n  mac_address = \"%[1]s\"\n  description = \"%[2]s\"\n  comments    = \"%[2]s\"\n}\n`, macAddress, testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"mac_address\", macAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"description\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"comments\", testSlug),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_mac_address\" \"test\" {\n  mac_address = \"%s\"\n}`, macAddress),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"mac_address\", macAddress),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_mac_address.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxMACAddress_customFields(t *testing.T) {\n\ttestSlug := \"mac-addr_cf\"\n\tmacAddress := \"00:1A:2B:3F:4D:5E\"\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name          = \"mac_custom_field\"\n  type          = \"text\"\n  content_types = [\"dcim.macaddress\"]\n}\n\nresource \"netbox_mac_address\" \"test\" {\n  mac_address   = \"%[1]s\"\n  description   = \"%[2]s\"\n  comments      = \"%[2]s\"\n  custom_fields = {\"${netbox_custom_field.test.name}\" = \"foomac\"}\n}\n`, macAddress, testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"custom_fields.mac_custom_field\", \"foomac\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_mac_address\" \"test\" {\n  mac_address = \"%s\"\n}`, macAddress),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"mac_address\", macAddress),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_mac_address.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxMACAddress_deviceByFieldName(t *testing.T) {\n\ttestSlug := \"mac-addr-dev-fn\"\n\tmacAddress := \"01:1A:2B:3C:4D:5E\"\n\tmacAddress2 := \"01:1A:2B:7C:4D:5E\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxMACAddressFullDeviceDependencies(testSlug) + fmt.Sprintf(`\nresource \"netbox_mac_address\" \"test\" {\n  mac_address = \"%[1]s\"\n  device_interface_id = netbox_device_interface.test.id\n  description = \"%[3]s\"\n}\n\nresource \"netbox_mac_address\" \"test2\" {\n  mac_address = \"%[2]s\"\n  device_interface_id = netbox_device_interface.test.id\n  description = \"%[3]s\"\n  comments    = \"%[3]s\"\n}`, macAddress, macAddress2, testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"mac_address\", macAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"description\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_mac_address.test\", \"device_interface_id\", \"netbox_device_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tRefreshState: true,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"mac_address\", macAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_device_interface.test\", \"mac_addresses.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_device_interface.test\", \"mac_addresses.0.id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_device_interface.test\", \"mac_addresses.0.mac_address\"),\n\t\t\t\t\tresource.TestCheckResourceAttrSet(\"netbox_device_interface.test\", \"mac_addresses.0.description\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_mac_address.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"device_interface_id\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxMACAddress_vmByFieldName(t *testing.T) {\n\ttestSlug := \"mac-addr-vm-fn\"\n\tmacAddress := \"02:1A:2B:3C:4D:5E\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxMACAddressFullVmDependencies(testSlug) + fmt.Sprintf(`\nresource \"netbox_mac_address\" \"test\" {\n  mac_address = \"%s\"\n  virtual_machine_interface_id = netbox_interface.test.id\n  description = \"%s\"\n}`, macAddress, testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"mac_address\", macAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"description\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_mac_address.test\", \"virtual_machine_interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_mac_address.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"virtual_machine_interface_id\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxMACAddress_deviceByObjectType(t *testing.T) {\n\ttestSlug := \"mac-addr-dev-ot\"\n\tmacAddress := \"03:1A:2B:3C:4D:5E\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxMACAddressFullDeviceDependencies(testSlug) + fmt.Sprintf(`\nresource \"netbox_mac_address\" \"test\" {\n  mac_address = \"%s\"\n  object_type = \"dcim.interface\"\n  interface_id = netbox_device_interface.test.id\n  description = \"%s\"\n}`, macAddress, testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"mac_address\", macAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"description\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"object_type\", \"dcim.interface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_mac_address.test\", \"interface_id\", \"netbox_device_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_mac_address.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"interface_id\", \"object_type\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxMACAddress_vmByObjectType(t *testing.T) {\n\ttestSlug := \"mac-addr-vm-ot\"\n\tmacAddress := \"04:1A:2B:3C:4D:5E\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxMACAddressFullVmDependencies(testSlug) + fmt.Sprintf(`\nresource \"netbox_mac_address\" \"test\" {\n  mac_address = \"%s\"\n  object_type = \"virtualization.vminterface\"\n  interface_id = netbox_interface.test.id\n  description = \"%s\"\n}`, macAddress, testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"mac_address\", macAddress),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"description\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_mac_address.test\", \"object_type\", \"virtualization.vminterface\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_mac_address.test\", \"interface_id\", \"netbox_interface.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_mac_address.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"interface_id\", \"object_type\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_mac_address\", &resource.Sweeper{\n\t\tName:         \"netbox_mac_address\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimMacAddressesListParams()\n\t\t\tres, err := api.Dcim.DcimMacAddressesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, macAddress := range res.GetPayload().Results {\n\t\t\t\tif len(macAddress.Tags) > 0 && (macAddress.Tags[0] == &models.NestedTag{Name: strToPtr(\"acctest\"), Slug: strToPtr(\"acctest\")}) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimMacAddressesDeleteParams().WithID(macAddress.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimMacAddressesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a mac address\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_manufacturer.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxManufacturer() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxManufacturerCreate,\n\t\tRead:   resourceNetboxManufacturerRead,\n\t\tUpdate: resourceNetboxManufacturerUpdate,\n\t\tDelete: resourceNetboxManufacturerDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/device-types/#manufacturers):\n\n> A manufacturer represents the \"make\" of a device; e.g. Cisco or Dell. Each device type must be assigned to a manufacturer. (Inventory items and platforms may also be associated with manufacturers.) Each manufacturer must have a unique name and may have a description assigned to it.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxManufacturerCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.Manufacturer{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := dcim.NewDcimManufacturersCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimManufacturersCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxManufacturerRead(d, m)\n}\n\nfunc resourceNetboxManufacturerRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimManufacturersReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimManufacturersRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimManufacturersReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\n\treturn nil\n}\n\nfunc resourceNetboxManufacturerUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.Manufacturer{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := dcim.NewDcimManufacturersPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Dcim.DcimManufacturersPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxManufacturerRead(d, m)\n}\n\nfunc resourceNetboxManufacturerDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimManufacturersDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimManufacturersDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimManufacturersDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_manufacturer_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxManufacturer_basic(t *testing.T) {\n\ttestSlug := \"manufacturer\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_manufacturer.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_manufacturer.test\", \"slug\", randomSlug),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_manufacturer.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_manufacturer\", &resource.Sweeper{\n\t\tName:         \"netbox_manufacturer\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimManufacturersListParams()\n\t\t\tres, err := api.Dcim.DcimManufacturersList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, manufacturer := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*manufacturer.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimManufacturersDeleteParams().WithID(manufacturer.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimManufacturersDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a device type\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_module.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxModule() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxModuleCreate,\n\t\tRead:   resourceNetboxModuleRead,\n\t\tUpdate: resourceNetboxModuleUpdate,\n\t\tDelete: resourceNetboxModuleDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/module/):\n\n> A module is a field-replaceable hardware component installed within a device which houses its own child components. The most common example is a chassis-based router or switch.\n\nSimilar to devices, modules are instantiated from module types, and any components associated with the module type are automatically instantiated on the new model. Each module must be installed within a module bay on a device, and each module bay may have only one module installed in it.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"module_bay_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"module_type_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tDescription:  \"One of [offline, active, planned, staged, failed, decommissioning]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"offline\", \"active\", \"planned\", \"staged\", \"failed\", \"decommissioning\"}, false),\n\t\t\t},\n\t\t\t\"serial\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"asset_tag\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxModuleCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableModule{\n\t\tDevice:      int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModuleBay:   int64ToPtr(int64(d.Get(\"module_bay_id\").(int))),\n\t\tModuleType:  int64ToPtr(int64(d.Get(\"module_type_id\").(int))),\n\t\tStatus:      d.Get(\"status\").(string),\n\t\tSerial:      getOptionalStr(d, \"serial\", false),\n\t\tDescription: getOptionalStr(d, \"description\", false),\n\t\tComments:    getOptionalStr(d, \"comments\", false),\n\t}\n\n\tif assetTag := getOptionalStr(d, \"asset_tag\", false); assetTag != \"\" {\n\t\tdata.AssetTag = &assetTag\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimModulesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimModulesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxModuleRead(d, m)\n}\n\nfunc resourceNetboxModuleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimModulesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimModulesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimModulesReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tmodule := res.GetPayload()\n\n\tif module.Device != nil {\n\t\td.Set(\"device_id\", module.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\tif module.ModuleBay != nil {\n\t\td.Set(\"module_bay_id\", module.ModuleBay.ID)\n\t} else {\n\t\td.Set(\"module_bay_id\", nil)\n\t}\n\n\tif module.ModuleType != nil {\n\t\td.Set(\"module_type_id\", module.ModuleType.ID)\n\t} else {\n\t\td.Set(\"module_type_id\", nil)\n\t}\n\n\tif module.Status != nil {\n\t\td.Set(\"status\", module.Status.Value)\n\t} else {\n\t\td.Set(\"status\", nil)\n\t}\n\n\td.Set(\"serial\", module.Serial)\n\td.Set(\"asset_tag\", module.AssetTag)\n\td.Set(\"description\", module.Description)\n\td.Set(\"comments\", module.Comments)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxModuleUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableModule{\n\t\tDevice:      int64ToPtr(int64(d.Get(\"device_id\").(int))),\n\t\tModuleBay:   int64ToPtr(int64(d.Get(\"module_bay_id\").(int))),\n\t\tModuleType:  int64ToPtr(int64(d.Get(\"module_type_id\").(int))),\n\t\tStatus:      d.Get(\"status\").(string),\n\t\tSerial:      getOptionalStr(d, \"serial\", true),\n\t\tDescription: getOptionalStr(d, \"description\", true),\n\t\tComments:    getOptionalStr(d, \"comments\", true),\n\t}\n\n\tif assetTag := getOptionalStr(d, \"asset_tag\", false); assetTag != \"\" {\n\t\tdata.AssetTag = &assetTag\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimModulesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimModulesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxModuleRead(d, m)\n}\n\nfunc resourceNetboxModuleDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimModulesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimModulesDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_module_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxModuleFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n\tdevice_type_id = netbox_device_type.test.id\n\ttenant_id = netbox_tenant.test.id\n\trole_id = netbox_device_role.test.id\n\tsite_id = netbox_site.test.id\n}\n\nresource \"netbox_device_module_bay\" \"test\" {\n\tdevice_id = netbox_device.test.id\n\tname = \"%[1]s\"\n}\n\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}`, testName)\n}\n\nfunc TestAccNetboxModule_basic(t *testing.T) {\n\ttestSlug := \"module_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckModuleDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxModuleFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_module\" \"test\" {\n\tdevice_id = netbox_device.test.id\n\tmodule_bay_id = netbox_device_module_bay.test.id\n\tmodule_type_id = netbox_module_type.test.id\n\tstatus = \"active\"\n\n\tserial = \"%[1]s_serial\"\n\tasset_tag = \"%[1]s_asset\"\n\tdescription = \"%[1]s_description\"\n  comments = \"%[1]s_comments\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"serial\", testName+\"_serial\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"asset_tag\", testName+\"_asset\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"comments\", testName+\"_comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_module.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_module.test\", \"module_bay_id\", \"netbox_device_module_bay.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_module.test\", \"module_type_id\", \"netbox_module_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxModuleFullDependencies(testName) + `\nresource \"netbox_module\" \"test\" {\n\tdevice_id = netbox_device.test.id\n\tmodule_bay_id = netbox_device_module_bay.test.id\n\tmodule_type_id = netbox_module_type.test.id\n\tstatus = \"offline\"\n}`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"status\", \"offline\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"serial\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"asset_tag\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module.test\", \"tags.#\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_module.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_module.test\", \"module_bay_id\", \"netbox_device_module_bay.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_module.test\", \"module_type_id\", \"netbox_module_type.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_module.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckModuleDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each module\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_module\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimModulesReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimModulesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"module (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimModulesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_module\", &resource.Sweeper{\n\t\tName:         \"netbox_module\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimModulesListParams()\n\t\t\tres, err := api.Dcim.DcimModulesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, module := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*module.ModuleType.Model, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimModulesDeleteParams().WithID(module.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimModulesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a module\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_module_type.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxModuleType() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxModuleTypeCreate,\n\t\tRead:   resourceNetboxModuleTypeRead,\n\t\tUpdate: resourceNetboxModuleTypeUpdate,\n\t\tDelete: resourceNetboxModuleTypeDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/moduletype/):\n\n> A module type represents a specific make and model of hardware component which is installable within a device's module bay and has its own child components. For example, consider a chassis-based switch or router with a number of field-replaceable line cards. Each line card has its own model number and includes a certain set of components such as interfaces. Each module type may have a manufacturer, model number, and part number assigned to it.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"manufacturer_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"model\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"part_number\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"weight\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"weight_unit\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"weight\"},\n\t\t\t\tDescription:  \"One of [kg, g, lb, oz]\",\n\t\t\t\tValidateFunc: validation.StringInSlice([]string{\"kg\", \"g\", \"lb\", \"oz\"}, false),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxModuleTypeCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableModuleType{\n\t\tManufacturer: int64ToPtr(int64(d.Get(\"manufacturer_id\").(int))),\n\t\tModel:        strToPtr(d.Get(\"model\").(string)),\n\t\tPartNumber:   getOptionalStr(d, \"part_number\", false),\n\t\tWeight:       getOptionalFloat(d, \"weight\"),\n\t\tWeightUnit:   getOptionalStr(d, \"weight_unit\", false),\n\t\tDescription:  getOptionalStr(d, \"description\", false),\n\t\tComments:     getOptionalStr(d, \"comments\", false),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimModuleTypesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimModuleTypesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxModuleTypeRead(d, m)\n}\n\nfunc resourceNetboxModuleTypeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimModuleTypesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimModuleTypesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimModuleTypesReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tmoduleType := res.GetPayload()\n\n\tif moduleType.Manufacturer != nil {\n\t\td.Set(\"manufacturer_id\", moduleType.Manufacturer.ID)\n\t} else {\n\t\td.Set(\"manufacturer_id\", nil)\n\t}\n\n\td.Set(\"model\", moduleType.Model)\n\td.Set(\"part_number\", moduleType.PartNumber)\n\td.Set(\"weight\", moduleType.Weight)\n\n\tif moduleType.WeightUnit != nil {\n\t\td.Set(\"weight_unit\", moduleType.WeightUnit.Value)\n\t} else {\n\t\td.Set(\"weight_unit\", nil)\n\t}\n\n\td.Set(\"description\", moduleType.Description)\n\td.Set(\"comments\", moduleType.Comments)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxModuleTypeUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritableModuleType{\n\t\tManufacturer: int64ToPtr(int64(d.Get(\"manufacturer_id\").(int))),\n\t\tModel:        strToPtr(d.Get(\"model\").(string)),\n\t\tPartNumber:   getOptionalStr(d, \"part_number\", true),\n\t\tWeight:       getOptionalFloat(d, \"weight\"),\n\t\tWeightUnit:   getOptionalStr(d, \"weight_unit\", false),\n\t\tDescription:  getOptionalStr(d, \"description\", true),\n\t\tComments:     getOptionalStr(d, \"comments\", true),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimModuleTypesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimModuleTypesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxModuleTypeRead(d, m)\n}\n\nfunc resourceNetboxModuleTypeDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimModuleTypesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimModuleTypesDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_module_type_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxModuleTypeFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"test\" {\n\tname = \"%[1]sa\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxModuleType_basic(t *testing.T) {\n\ttestSlug := \"module_type_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckModuleTypeDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxModuleTypeFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n  part_number = \"%[1]s_pn\"\n  description = \"%[1]s_description\"\n  comments = \"%[1]s_comments\"\n\n  weight = 1\n  weight_unit = \"kg\"\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"model\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"part_number\", testName+\"_pn\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"description\", testName+\"_description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"comments\", testName+\"_comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"weight\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"weight_unit\", \"kg\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_module_type.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxModuleTypeFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_module_type\" \"test\" {\n  manufacturer_id = netbox_manufacturer.test.id\n  model = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"model\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"part_number\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"weight\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"weight_unit\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_module_type.test\", \"tags.#\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_module_type.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_module_type.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckModuleTypeDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each module type\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_module_type\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimModuleTypesReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimModuleTypesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"module type (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimModuleTypesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_module_type\", &resource.Sweeper{\n\t\tName:         \"netbox_module_type\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimModuleTypesListParams()\n\t\t\tres, err := api.Dcim.DcimModuleTypesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, moduleType := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*moduleType.Model, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimModuleTypesDeleteParams().WithID(moduleType.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimModuleTypesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a module_type\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_permission.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/users\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxPermission() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxPermissionCreate,\n\t\tRead:   resourceNetboxPermissionRead,\n\t\tUpdate: resourceNetboxPermissionUpdate,\n\t\tDelete: resourceNetboxPermissionDelete,\n\t\tDescription: `:meta:subcategory:Authentication:This resource manages the object-based permissions for Netbox users, built into the application.\n\n> Object-based permissions enable an administrator to grant users or groups the ability to perform an action on arbitrary subsets of objects in NetBox, rather than all objects of a certain type.\n> For more information, see the [Netbox Object-Based Permissions Docs.](https://docs.netbox.dev/en/stable/administration/permissions/)`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tDescription: \"The name of the permission object.\",\n\t\t\t\tRequired:    true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tDescription: \"The description of the permission object.\",\n\t\t\t\tOptional:    true,\n\t\t\t},\n\t\t\t\"enabled\": {\n\t\t\t\tType:        schema.TypeBool,\n\t\t\t\tDescription: \"Whether the permission object is enabled or not.\",\n\t\t\t\tOptional:    true,\n\t\t\t\tDefault:     true,\n\t\t\t},\n\t\t\t\"object_types\": {\n\t\t\t\tType: schema.TypeSet,\n\t\t\t\tDescription: \"A list of object types that the permission object allows access to. Should be in a form \" +\n\t\t\t\t\t\"the API can accept. For example: `circuits.provider`, `dcim.inventoryitem`, etc.\",\n\t\t\t\tRequired: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"groups\": {\n\t\t\t\tType:        schema.TypeSet,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"A list of group IDs that have been assigned to this permission object.\",\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"users\": {\n\t\t\t\tType:        schema.TypeSet,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"A list of user IDs that have been assigned to this permission object.\",\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"actions\": {\n\t\t\t\tType:        schema.TypeSet,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: \"A list actions that are allowed on the object types. Acceptable values are `view`, `add`, `change`, or `delete`.\",\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"constraints\": {\n\t\t\t\tType: schema.TypeString,\n\t\t\t\tDescription: \"A JSON string of an arbitrary filter used to limit the granted action(s) to a specific subset of objects. \" +\n\t\t\t\t\t\"For more information on correct syntax, see https://docs.netbox.dev/en/stable/administration/permissions/#constraints \",\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringIsJSON,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\nfunc resourceNetboxPermissionCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableObjectPermission{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tdata.Description = d.Get(\"description\").(string)\n\tdata.Enabled = d.Get(\"enabled\").(bool)\n\n\tdata.ObjectTypes = toStringList(d.Get(\"object_types\"))\n\tdata.Groups = toInt64List(d.Get(\"groups\"))\n\tdata.Users = toInt64List(d.Get(\"users\"))\n\tdata.Actions = toStringList(d.Get(\"actions\"))\n\n\tvar constraints interface{}\n\tc := d.Get(\"constraints\").(string)\n\tif c == \"\" {\n\t\tdata.Constraints = nil\n\t} else {\n\t\terr := json.Unmarshal([]byte(c), &constraints)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch v := constraints.(type) {\n\t\tcase []interface{}:\n\t\t\tdata.Constraints = v\n\t\tcase map[string]interface{}:\n\t\t\tdata.Constraints = v\n\t\t}\n\t}\n\n\tparams := users.NewUsersPermissionsCreateParams().WithData(&data)\n\tres, err := api.Users.UsersPermissionsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxPermissionRead(d, m)\n}\n\nfunc resourceNetboxPermissionRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := users.NewUsersPermissionsReadParams().WithID(id)\n\n\tres, err := api.Users.UsersPermissionsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*users.UsersPermissionsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"description\", res.GetPayload().Description)\n\td.Set(\"enabled\", res.GetPayload().Enabled)\n\td.Set(\"object_types\", res.GetPayload().ObjectTypes)\n\n\tvar groups []int\n\tfor _, v := range res.GetPayload().Groups {\n\t\tgroups = append(groups, int(v.ID))\n\t}\n\td.Set(\"groups\", groups)\n\n\tvar users []int\n\tfor _, v := range res.GetPayload().Users {\n\t\tusers = append(users, int(v.ID))\n\t}\n\td.Set(\"users\", users)\n\n\td.Set(\"actions\", res.GetPayload().Actions)\n\n\tif res.GetPayload().Constraints == nil {\n\t\td.Set(\"constraints\", \"\")\n\t\treturn nil\n\t}\n\n\tb, err := json.Marshal(res.GetPayload().Constraints)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.Set(\"constraints\", string(b))\n\n\treturn nil\n}\n\nfunc resourceNetboxPermissionUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableObjectPermission{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tdata.Description = d.Get(\"description\").(string)\n\tdata.Enabled = d.Get(\"enabled\").(bool)\n\n\tdata.ObjectTypes = toStringList(d.Get(\"object_types\"))\n\tdata.Groups = toInt64List(d.Get(\"groups\"))\n\tdata.Users = toInt64List(d.Get(\"users\"))\n\tdata.Actions = toStringList(d.Get(\"actions\"))\n\n\tvar constraints interface{}\n\tc := d.Get(\"constraints\").(string)\n\tif c == \"\" {\n\t\tdata.Constraints = nil\n\t} else {\n\t\terr := json.Unmarshal([]byte(c), &constraints)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch v := constraints.(type) {\n\t\tcase []interface{}:\n\t\t\tdata.Constraints = v\n\t\tcase map[string]interface{}:\n\t\t\tdata.Constraints = v\n\t\t}\n\t}\n\tparams := users.NewUsersPermissionsUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Users.UsersPermissionsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxPermissionRead(d, m)\n}\n\nfunc resourceNetboxPermissionDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := users.NewUsersPermissionsDeleteParams().WithID(id)\n\t_, err := api.Users.UsersPermissionsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*users.UsersPermissionsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_permission_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/users\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxPermission_basic(t *testing.T) {\n\ttestSlug := \"user_permissions\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_permission\" \"test_basic\" {\n  name = \"%s\"\n  description = \"This is a terraform test.\"\n  enabled = true\n  object_types = [\"ipam.prefix\"]\n  actions = [\"add\", \"change\"]\n  users = [1]\n  constraints = jsonencode([{\n    \"status\" = \"active\"\n  }])\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"description\", \"This is a terraform test.\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"enabled\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"object_types.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"object_types.0\", \"ipam.prefix\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"actions.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"actions.0\", \"add\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"actions.1\", \"change\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"users.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"users.0\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"constraints\", \"[{\\\"status\\\":\\\"active\\\"}]\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_permission.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: false,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPermission_noConstraint(t *testing.T) {\n\ttestSlug := \"user_perms_nocnstrnt\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_permission\" \"test_basic\" {\n  name = \"%s\"\n  description = \"This is a terraform test.\"\n  enabled = true\n  object_types = [\"ipam.prefix\"]\n  actions = [\"add\", \"change\"]\n  users = [1]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_permission.test_basic\", \"name\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_permission.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: false,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_permission\", &resource.Sweeper{\n\t\tName:         \"netbox_permission\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := users.NewUsersPermissionsListParams()\n\t\t\tres, err := api.Users.UsersPermissionsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, perm := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*perm.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := users.NewUsersPermissionsDeleteParams().WithID(perm.ID)\n\t\t\t\t\t_, err := api.Users.UsersPermissionsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a user\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_platform.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxPlatform() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxPlatformCreate,\n\t\tRead:   resourceNetboxPlatformRead,\n\t\tUpdate: resourceNetboxPlatformUpdate,\n\t\tDelete: resourceNetboxPlatformDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#platforms):\n\n> A platform defines the type of software running on a device or virtual machine. This can be helpful to model when it is necessary to distinguish between different versions or feature sets. Note that two devices of the same type may be assigned different platforms: For example, one Juniper MX240 might run Junos 14 while another runs Junos 15.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"manufacturer_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxPlatformCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata := models.WritablePlatform{\n\t\tName: &name,\n\t\tSlug: &slug,\n\t\tTags: []*models.NestedTag{},\n\t}\n\n\tmanufacturerIDValue, ok := d.GetOk(\"manufacturer_id\")\n\tif ok {\n\t\tdata.Manufacturer = int64ToPtr(int64(manufacturerIDValue.(int)))\n\t}\n\n\tparams := dcim.NewDcimPlatformsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimPlatformsCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxPlatformRead(d, m)\n}\n\nfunc resourceNetboxPlatformRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPlatformsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimPlatformsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimPlatformsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tresult := res.GetPayload()\n\n\td.Set(\"name\", result.Name)\n\td.Set(\"slug\", result.Slug)\n\tif result.Manufacturer != nil {\n\t\td.Set(\"manufacturer_id\", result.Manufacturer.ID)\n\t}\n\treturn nil\n}\n\nfunc resourceNetboxPlatformUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritablePlatform{}\n\n\tname := d.Get(\"name\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.Tags = []*models.NestedTag{}\n\n\tmanufacturerIDValue, ok := d.GetOk(\"manufacturer_id\")\n\tif ok {\n\t\tdata.Manufacturer = int64ToPtr(int64(manufacturerIDValue.(int)))\n\t}\n\n\tparams := dcim.NewDcimPlatformsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Dcim.DcimPlatformsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxPlatformRead(d, m)\n}\n\nfunc resourceNetboxPlatformDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPlatformsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimPlatformsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimPlatformsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_platform_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxPlatform_basic(t *testing.T) {\n\ttestSlug := \"platform_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_platform\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_platform.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_platform.test\", \"slug\", randomSlug),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_platform.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPlatform_manufacturer(t *testing.T) {\n\ttestSlug := \"platform_manufacturer\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestManufacturer := \"manu_test\"\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[3]s\"\n}\n\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}`, testName, randomSlug, testManufacturer),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_platform.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_platform.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_platform.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_platform.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPlatform_defaultSlug(t *testing.T) {\n\ttestSlug := \"platform_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_platform\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_platform.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_platform.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_platform\", &resource.Sweeper{\n\t\tName:         \"netbox_platform\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimPlatformsListParams()\n\t\t\tres, err := api.Dcim.DcimPlatformsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, platform := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*platform.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimPlatformsDeleteParams().WithID(platform.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimPlatformsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a platform\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_power_panel.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxPowerPanel() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxPowerPanelCreate,\n\t\tRead:   resourceNetboxPowerPanelRead,\n\t\tUpdate: resourceNetboxPowerPanelUpdate,\n\t\tDelete: resourceNetboxPowerPanelDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/powerpanel/):\n\n> A power panel represents the origin point in NetBox for electrical power being disseminated by one or more power feeds. In a data center environment, one power panel often serves a group of racks, with an individual power feed extending to each rack, though this is not always the case. It is common to have two sets of panels and feeds arranged in parallel to provide redundant power to each rack.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxPowerPanelCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritablePowerPanel{\n\t\tSite:        int64ToPtr(int64(d.Get(\"site_id\").(int))),\n\t\tName:        strToPtr(d.Get(\"name\").(string)),\n\t\tLocation:    getOptionalInt(d, \"location_id\"),\n\t\tDescription: getOptionalStr(d, \"description\", false),\n\t\tComments:    getOptionalStr(d, \"comments\", false),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimPowerPanelsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimPowerPanelsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxPowerPanelRead(d, m)\n}\n\nfunc resourceNetboxPowerPanelRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPowerPanelsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimPowerPanelsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimPowerPanelsReadDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tpowerPanel := res.GetPayload()\n\n\tif powerPanel.Site != nil {\n\t\td.Set(\"site_id\", powerPanel.Site.ID)\n\t} else {\n\t\td.Set(\"site_id\", nil)\n\t}\n\n\td.Set(\"name\", powerPanel.Name)\n\n\tif powerPanel.Location != nil {\n\t\td.Set(\"location_id\", powerPanel.Location.ID)\n\t} else {\n\t\td.Set(\"location_id\", nil)\n\t}\n\n\td.Set(\"description\", powerPanel.Description)\n\td.Set(\"comments\", powerPanel.Comments)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxPowerPanelUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tdata := models.WritablePowerPanel{\n\t\tSite:        int64ToPtr(int64(d.Get(\"site_id\").(int))),\n\t\tName:        strToPtr(d.Get(\"name\").(string)),\n\t\tLocation:    getOptionalInt(d, \"location_id\"),\n\t\tDescription: getOptionalStr(d, \"description\", true),\n\t\tComments:    getOptionalStr(d, \"comments\", true),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimPowerPanelsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimPowerPanelsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxPowerPanelRead(d, m)\n}\n\nfunc resourceNetboxPowerPanelDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimPowerPanelsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimPowerPanelsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_power_panel_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc testAccNetboxPowerPanelFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name = \"%[1]s\"\n  site_id =netbox_site.test.id\n}\n\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}`, testName)\n}\n\nfunc TestAccNetboxPowerPanel_basic(t *testing.T) {\n\ttestSlug := \"power_panel_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tCheckDestroy: testAccCheckPowerPanelDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPowerPanelFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_power_panel\" \"test\" {\n  name = \"%[1]s\"\n  description = \"%[1]sdescription\"\n  comments = \"%[1]scomments\"\n\n  site_id = netbox_site.test.id\n  location_id = netbox_location.test.id\n  tags = [netbox_tag.test_a.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"description\", testName+\"description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"comments\", testName+\"comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"tags.0\", testName+\"a\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_power_panel.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_power_panel.test\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPowerPanelFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_power_panel\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_power_panel.test\", \"location_id\", \"0\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_power_panel.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_power_panel.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckPowerPanelDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each power panel\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_power_panel\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our device by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimPowerPanelsReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimPowerPanelsRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"power panel (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimPowerPanelsReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_power_panel\", &resource.Sweeper{\n\t\tName:         \"netbox_power_panel\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimPowerPanelsListParams()\n\t\t\tres, err := api.Dcim.DcimPowerPanelsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, powerPanel := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*powerPanel.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimPowerPanelsDeleteParams().WithID(powerPanel.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimPowerPanelsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a power_panel\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_prefix.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxPrefixStatusOptions = []string{\"active\", \"container\", \"reserved\", \"deprecated\"}\n\nfunc resourceNetboxPrefix() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxPrefixCreate,\n\t\tRead:   resourceNetboxPrefixRead,\n\t\tUpdate: resourceNetboxPrefixUpdate,\n\t\tDelete: resourceNetboxPrefixDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#prefixes):\n\n> A prefix is an IPv4 or IPv6 network and mask expressed in CIDR notation (e.g. 192.0.2.0/24). A prefix entails only the \"network portion\" of an IP address: All bits in the address not covered by the mask must be zero. (In other words, a prefix cannot be a specific IP address.)\n>\n> Prefixes are automatically organized by their parent aggregates. Additionally, each prefix can be assigned to a particular site and virtual routing and forwarding instance (VRF). Each VRF represents a separate IP space or routing table. All prefixes not assigned to a VRF are considered to be in the \"global\" table.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"prefix\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.IsCIDR,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxPrefixStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxPrefixStatusOptions),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"is_pool\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"mark_utilized\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"vrf_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"site_id\", \"site_group_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_group_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"site_group_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_id\", \"region_id\"},\n\t\t\t},\n\t\t\t\"region_id\": {\n\t\t\t\tType:          schema.TypeInt,\n\t\t\t\tOptional:      true,\n\t\t\t\tConflictsWith: []string{\"location_id\", \"site_id\", \"site_group_id\"},\n\t\t\t},\n\t\t\t\"vlan_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t\ttagsKey:         tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\nfunc resourceNetboxPrefixCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritablePrefix{}\n\n\tprefix := d.Get(\"prefix\").(string)\n\tstatus := d.Get(\"status\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tisPool := d.Get(\"is_pool\").(bool)\n\tmarkUtilized := d.Get(\"mark_utilized\").(bool)\n\n\tdata.Prefix = &prefix\n\tdata.Status = status\n\n\tdata.Description = description\n\tdata.IsPool = isPool\n\n\tdata.MarkUtilized = markUtilized\n\n\tif vrfID, ok := d.GetOk(\"vrf_id\"); ok {\n\t\tdata.Vrf = int64ToPtr(int64(vrfID.(int)))\n\t}\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\n\tif vlanID, ok := d.GetOk(\"vlan_id\"); ok {\n\t\tdata.Vlan = int64ToPtr(int64(vlanID.(int)))\n\t}\n\n\tif roleID, ok := d.GetOk(\"role_id\"); ok {\n\t\tdata.Role = int64ToPtr(int64(roleID.(int)))\n\t}\n\n\tsiteID := getOptionalInt(d, \"site_id\")\n\tsiteGroupID := getOptionalInt(d, \"site_group_id\")\n\tlocationID := getOptionalInt(d, \"location_id\")\n\tregionID := getOptionalInt(d, \"region_id\")\n\n\tswitch {\n\tcase siteID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.site\")\n\t\tdata.ScopeID = siteID\n\tcase siteGroupID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.sitegroup\")\n\t\tdata.ScopeID = siteGroupID\n\tcase locationID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.location\")\n\t\tdata.ScopeID = locationID\n\tcase regionID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.region\")\n\t\tdata.ScopeID = regionID\n\tdefault:\n\t\tdata.ScopeType = nil\n\t\tdata.ScopeID = nil\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamPrefixesCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamPrefixesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxPrefixRead(d, m)\n}\n\nfunc resourceNetboxPrefixRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamPrefixesReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamPrefixesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamPrefixesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tprefix := res.GetPayload()\n\td.Set(\"description\", prefix.Description)\n\td.Set(\"is_pool\", prefix.IsPool)\n\td.Set(\"mark_utilized\", prefix.MarkUtilized)\n\tif prefix.Status != nil {\n\t\td.Set(\"status\", prefix.Status.Value)\n\t}\n\tif prefix.Prefix != nil {\n\t\td.Set(\"prefix\", prefix.Prefix)\n\t}\n\n\tif prefix.Vrf != nil {\n\t\td.Set(\"vrf_id\", prefix.Vrf.ID)\n\t} else {\n\t\td.Set(\"vrf_id\", nil)\n\t}\n\n\tif prefix.Tenant != nil {\n\t\td.Set(\"tenant_id\", prefix.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tif prefix.Vlan != nil {\n\t\td.Set(\"vlan_id\", prefix.Vlan.ID)\n\t} else {\n\t\td.Set(\"vlan_id\", nil)\n\t}\n\n\tif prefix.Role != nil {\n\t\td.Set(\"role_id\", prefix.Role.ID)\n\t} else {\n\t\td.Set(\"role_id\", nil)\n\t}\n\n\td.Set(\"site_id\", nil)\n\td.Set(\"site_group_id\", nil)\n\td.Set(\"location_id\", nil)\n\td.Set(\"region_id\", nil)\n\n\tif prefix.ScopeType != nil && prefix.ScopeID != nil {\n\t\tscopeID := prefix.ScopeID\n\t\tswitch scopeType := prefix.ScopeType; *scopeType {\n\t\tcase \"dcim.site\":\n\t\t\td.Set(\"site_id\", scopeID)\n\t\tcase \"dcim.sitegroup\":\n\t\t\td.Set(\"site_group_id\", scopeID)\n\t\tcase \"dcim.location\":\n\t\t\td.Set(\"location_id\", scopeID)\n\t\tcase \"dcim.region\":\n\t\t\td.Set(\"region_id\", scopeID)\n\t\t}\n\t}\n\tcf := getCustomFields(prefix.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\tapi.readTags(d, prefix.Tags)\n\t// FIGURE OUT NESTED VRF AND NESTED VLAN (from maybe interfaces?)\n\n\treturn nil\n}\n\nfunc resourceNetboxPrefixUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritablePrefix{}\n\tprefix := d.Get(\"prefix\").(string)\n\tstatus := d.Get(\"status\").(string)\n\tisPool := d.Get(\"is_pool\").(bool)\n\tmarkUtilized := d.Get(\"mark_utilized\").(bool)\n\n\tdata.Prefix = &prefix\n\tdata.Status = status\n\n\tdata.IsPool = isPool\n\tdata.MarkUtilized = markUtilized\n\n\tif description, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = description.(string)\n\t} else {\n\t\tdata.Description = \" \"\n\t}\n\n\tif vrfID, ok := d.GetOk(\"vrf_id\"); ok {\n\t\tdata.Vrf = int64ToPtr(int64(vrfID.(int)))\n\t}\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\n\tif vlanID, ok := d.GetOk(\"vlan_id\"); ok {\n\t\tdata.Vlan = int64ToPtr(int64(vlanID.(int)))\n\t}\n\n\tif roleID, ok := d.GetOk(\"role_id\"); ok {\n\t\tdata.Role = int64ToPtr(int64(roleID.(int)))\n\t}\n\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tsiteID := getOptionalInt(d, \"site_id\")\n\tsiteGroupID := getOptionalInt(d, \"site_group_id\")\n\tlocationID := getOptionalInt(d, \"location_id\")\n\tregionID := getOptionalInt(d, \"region_id\")\n\n\tswitch {\n\tcase siteID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.site\")\n\t\tdata.ScopeID = siteID\n\tcase siteGroupID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.sitegroup\")\n\t\tdata.ScopeID = siteGroupID\n\tcase locationID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.location\")\n\t\tdata.ScopeID = locationID\n\tcase regionID != nil:\n\t\tdata.ScopeType = strToPtr(\"dcim.region\")\n\t\tdata.ScopeID = regionID\n\tdefault:\n\t\tdata.ScopeType = nil\n\t\tdata.ScopeID = nil\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamPrefixesUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Ipam.IpamPrefixesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxPrefixRead(d, m)\n}\n\nfunc resourceNetboxPrefixDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamPrefixesDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamPrefixesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamPrefixesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_prefix_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxPrefixFullDependencies(testName string, testSlug string, testVid string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_vrf\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_ipam_role\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n}\n\nresource \"netbox_vlan\" \"test\" {\n  name = \"%[1]s\"\n  vid = \"%[3]s\"\n  status = \"active\"\n  description = \"Test\"\n  tags = []\n}\n`, testName, testSlug, testVid)\n}\n\nfunc TestAccNetboxPrefix_basic(t *testing.T) {\n\ttestPrefix := \"1.1.1.128/25\"\n\ttestSlug := \"prefix\"\n\ttestVid := \"123\"\n\trandomSlug := testAccGetTestName(testSlug)\n\ttestDesc := \"test prefix\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s\"\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n  mark_utilized = true\n  is_pool = true\n}`, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"description\", testDesc),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"mark_utilized\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"is_pool\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s\"\n  status = \"provoke_error\"\n  tags = [netbox_tag.test.name]\n  mark_utilized = true\n}`, testPrefix, testDesc),\n\t\t\t\tExpectError: regexp.MustCompile(\"expected status to be one of .*\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s\"\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n  mark_utilized = false\n  is_pool = false\n}`, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"mark_utilized\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"is_pool\", \"false\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s\"\n  status = \"deprecated\"\n  tags = [netbox_tag.test.name]\n  mark_utilized = true\n}`, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"status\", \"deprecated\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s\"\n  status = \"container\"\n  tags = [netbox_tag.test.name]\n  mark_utilized = true\n}`, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"status\", \"container\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s 2\"\n  status = \"active\"\n  tags = [netbox_tag.test.name]\n  mark_utilized = true\n}`, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"description\", fmt.Sprintf(\"%s 2\", testDesc)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"vrf_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tenant_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"site_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"mark_utilized\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s 2\"\n  status = \"active\"\n  vrf_id = netbox_vrf.test.id\n  tenant_id = netbox_tenant.test.id\n  tags = [netbox_tag.test.name]\n  mark_utilized = true\n}`, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"description\", fmt.Sprintf(\"%s 2\", testDesc)),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"vrf_id\", \"netbox_vrf.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"mark_utilized\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s 2\"\n  status = \"active\"\n  vrf_id = netbox_vrf.test.id\n  tenant_id = netbox_tenant.test.id\n  site_id = netbox_site.test.id\n  vlan_id = netbox_vlan.test.id\n  role_id = netbox_ipam_role.test.id\n  tags = [netbox_tag.test.name]\n  mark_utilized = true\n}`, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"description\", fmt.Sprintf(\"%s 2\", testDesc)),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"vrf_id\", \"netbox_vrf.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"vlan_id\", \"netbox_vlan.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"role_id\", \"netbox_ipam_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"mark_utilized\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s 2\"\n  status = \"active\"\n}`, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"description\", fmt.Sprintf(\"%s 2\", testDesc)),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  status = \"active\"\n}`, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"prefix\", testPrefix),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"status\", \"active\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_prefix.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPrefix_cf(t *testing.T) {\n\ttestPrefix := \"1.1.2.128/25\"\n\ttestSlug := \"prefix_cf\"\n\ttestVid := \"124\"\n\trandomSlug := testAccGetTestName(testSlug)\n\ttestDesc := \"test cf prefix\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name   = \"%s\"\n  type   = \"text\"\n  weight = 100\n  content_types = [\"ipam.prefix\"]\n}\n\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  description = \"%s 2\"\n  status = \"active\"\n  mark_utilized = true\n\n  custom_fields = {\n    \"${netbox_custom_field.test.name}\" = \"test-field\"\n  }\n}`, testSlug, testPrefix, testDesc),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", fmt.Sprintf(\"custom_fields.%s\", testSlug), \"test-field\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_prefix.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPrefix_scopes(t *testing.T) {\n\ttestPrefix := \"1.8.1.128/25\"\n\ttestPrefix2 := \"1.8.2.128/25\"\n\ttestPrefix3 := \"1.8.3.128/25\"\n\ttestSlug := \"prefix-scopes\"\n\ttestVid := \"333\"\n\trandomSlug := testAccGetTestName(testSlug)\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  status = \"active\"\n}`, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"site_id\", \"0\"),\n\t\t\t\t\t// resource.TestCheckNoResourceAttr(\"netbox_prefix.test\", \"site_id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"site_group_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"region_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"location_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  status = \"active\"\n  site_id = netbox_site.test.id\n}`, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"site_group_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"region_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"location_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_location\" \"test\" {\n  name = \"%s\"\n  site_id = netbox_site.test.id\n}\nresource \"netbox_prefix\" \"test\" {\n  prefix = \"%s\"\n  status = \"active\"\n  location_id = netbox_location.test.id\n}`, testSlug, testPrefix),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"site_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"site_group_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test\", \"region_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_region\" \"test\" {\n  name = \"%s\"\n}\nresource \"netbox_prefix\" \"test2\" {\n  prefix = \"%s\"\n  status = \"active\"\n  region_id = netbox_region.test.id\n}`, testSlug, testPrefix2),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test2\", \"site_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test2\", \"site_group_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test2\", \"region_id\", \"netbox_region.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test2\", \"location_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`\nresource \"netbox_site_group\" \"test\" {\n  name = \"%s\"\n}\nresource \"netbox_prefix\" \"test3\" {\n  prefix = \"%s\"\n  status = \"active\"\n  site_group_id = netbox_site_group.test.id\n}`, testSlug, testPrefix3),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test3\", \"site_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_prefix.test3\", \"site_group_id\", \"netbox_site_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test3\", \"region_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_prefix.test3\", \"location_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_prefix.test3\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_prefix\", &resource.Sweeper{\n\t\tName:         \"netbox_prefix\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamPrefixesListParams()\n\t\t\tres, err := api.Ipam.IpamPrefixesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, prefix := range res.GetPayload().Results {\n\t\t\t\tif len(prefix.Tags) > 0 && (prefix.Tags[0] == &models.NestedTag{Name: strToPtr(\"acctest\"), Slug: strToPtr(\"acctest\")}) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamPrefixesDeleteParams().WithID(prefix.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamPrefixesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a prefix\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_primary_ip.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxPrimaryIP() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxPrimaryIPCreate,\n\t\tRead:   resourceNetboxPrimaryIPRead,\n\t\tUpdate: resourceNetboxPrimaryIPUpdate,\n\t\tDelete: resourceNetboxPrimaryIPDelete,\n\n\t\tDescription: `:meta:subcategory:Virtualization:This resource is used to define the primary IP for a given virtual machine. The primary IP is reflected in the Virtual machine Netbox UI, which identifies the Primary IPv4 and IPv6 addresses.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"virtual_machine_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"ip_address_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"ip_address_version\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tValidateFunc: validation.IntInSlice([]int{4, 6}),\n\t\t\t\tOptional:     true,\n\t\t\t\tDefault:      4,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxPrimaryIPCreate(d *schema.ResourceData, m interface{}) error {\n\td.SetId(strconv.Itoa(d.Get(\"virtual_machine_id\").(int)))\n\n\treturn resourceNetboxPrimaryIPUpdate(d, m)\n}\n\nfunc resourceNetboxPrimaryIPRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationVirtualMachinesReadParams().WithID(id)\n\n\tres, err := api.Virtualization.VirtualizationVirtualMachinesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationVirtualMachinesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tIPAddressVersion := d.Get(\"ip_address_version\")\n\td.Set(\"ip_address_version\", IPAddressVersion)\n\n\tif IPAddressVersion == 4 && res.GetPayload().PrimaryIp4 != nil {\n\t\td.Set(\"ip_address_id\", res.GetPayload().PrimaryIp4.ID)\n\t} else if IPAddressVersion == 6 && res.GetPayload().PrimaryIp6 != nil {\n\t\td.Set(\"ip_address_id\", res.GetPayload().PrimaryIp6.ID)\n\t} else {\n\t\t// if the vm exists, but has no primary ip, consider this element deleted\n\t\td.SetId(\"\")\n\t\treturn nil\n\t}\n\td.Set(\"virtual_machine_id\", res.GetPayload().ID)\n\treturn nil\n}\n\nfunc resourceNetboxPrimaryIPUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tvirtualMachineID := int64(d.Get(\"virtual_machine_id\").(int))\n\tIPAddressID := int64(d.Get(\"ip_address_id\").(int))\n\tIPAddressVersion := int64(d.Get(\"ip_address_version\").(int))\n\n\t// because the go-netbox library does not have patch support atm, we have to get the whole object and re-put it\n\n\t// first, get the vm\n\treadParams := virtualization.NewVirtualizationVirtualMachinesReadParams().WithID(virtualMachineID)\n\tres, err := api.Virtualization.VirtualizationVirtualMachinesRead(readParams, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvm := res.GetPayload()\n\n\t// then update the FULL vm with ALL tracked attributes\n\tdata := models.WritableVirtualMachineWithConfigContext{}\n\tdata.Name = vm.Name\n\tdata.Tags = vm.Tags\n\t// the netbox API sends the URL property as part of NestedTag, but it does not accept the URL property when we send it back\n\t// so set it to empty\n\t// display too\n\tfor _, tag := range data.Tags {\n\t\ttag.URL = \"\"\n\t\ttag.Display = \"\"\n\t}\n\tdata.Comments = vm.Comments\n\tdata.Description = vm.Description\n\tdata.Memory = vm.Memory\n\tdata.Vcpus = vm.Vcpus\n\tdata.Disk = vm.Disk\n\n\tif vm.Cluster != nil {\n\t\tdata.Cluster = &vm.Cluster.ID\n\t}\n\n\tif vm.Site != nil {\n\t\tdata.Site = &vm.Site.ID\n\t}\n\n\tif vm.PrimaryIp4 != nil {\n\t\tdata.PrimaryIp4 = &vm.PrimaryIp4.ID\n\t}\n\n\tif vm.PrimaryIp6 != nil {\n\t\tdata.PrimaryIp6 = &vm.PrimaryIp6.ID\n\t}\n\n\tif vm.Platform != nil {\n\t\tdata.Platform = &vm.Platform.ID\n\t}\n\n\tif vm.Tenant != nil {\n\t\tdata.Tenant = &vm.Tenant.ID\n\t}\n\n\tif vm.Role != nil {\n\t\tdata.Role = &vm.Role.ID\n\t}\n\n\tif vm.Device != nil {\n\t\tdata.Device = &vm.Device.ID\n\t}\n\n\tif vm.LocalContextData != nil {\n\t\tdata.LocalContextData = vm.LocalContextData\n\t}\n\n\t// unset primary ip address if -1 is passed as id\n\tif IPAddressID == -1 {\n\t\tif IPAddressVersion == 4 {\n\t\t\tdata.PrimaryIp4 = nil\n\t\t} else {\n\t\t\tdata.PrimaryIp6 = nil\n\t\t}\n\t} else {\n\t\tif IPAddressVersion == 4 {\n\t\t\tdata.PrimaryIp4 = &IPAddressID\n\t\t} else {\n\t\t\tdata.PrimaryIp6 = &IPAddressID\n\t\t}\n\t}\n\n\tupdateParams := virtualization.NewVirtualizationVirtualMachinesUpdateParams().WithID(virtualMachineID).WithData(&data)\n\n\t_, err = api.Virtualization.VirtualizationVirtualMachinesUpdate(updateParams, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxPrimaryIPRead(d, m)\n}\n\nfunc resourceNetboxPrimaryIPDelete(d *schema.ResourceData, m interface{}) error {\n\t// Set ip_address_id to minus one and go to update. Update will set nil\n\td.Set(\"ip_address_id\", -1)\n\treturn resourceNetboxPrimaryIPUpdate(d, m)\n}\n"
  },
  {
    "path": "netbox/resource_netbox_primary_ip_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxPrimaryIPFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  site_id = netbox_site.test.id\n  device_type_id = netbox_device_type.test.id\n  cluster_id = netbox_cluster.test.id\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  comments = \"thisisacomment\"\n  memory_mb = 1024\n  disk_size_mb = 256\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  platform_id = netbox_platform.test.id\n  vcpus = \"4\"\n  status = \"planned\"\n  device_id = netbox_device.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value\"})\n\n  tags = [netbox_tag.test.name]\n}\n\nresource \"netbox_interface\" \"test\" {\n  virtual_machine_id = netbox_virtual_machine.test.id\n  name = \"%[1]s\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxPrimaryIP4_basic(t *testing.T) {\n\ttestSlug := \"pr_ip_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrimaryIPFullDependencies(testName) + `\nresource \"netbox_ip_address\" \"test_v4\" {\n  ip_address = \"1.1.1.13/32\"\n  status = \"active\"\n  virtual_machine_interface_id = netbox_interface.test.id\n}\n\nresource \"netbox_primary_ip\" \"test_v4\" {\n  virtual_machine_id = netbox_virtual_machine.test.id\n  ip_address_id = netbox_ip_address.test_v4.id\n}`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_primary_ip.test_v4\", \"virtual_machine_id\", \"netbox_virtual_machine.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_primary_ip.test_v4\", \"ip_address_id\", \"netbox_ip_address.test_v4\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"memory_mb\", \"1024\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"vcpus\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"disk_size_mb\", \"256\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"status\", \"planned\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxPrimaryIP6_basic(t *testing.T) {\n\ttestSlug := \"pr_ipv6_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxPrimaryIPFullDependencies(testName) + `\n\nresource \"netbox_ip_address\" \"test_v6\" {\n  ip_address = \"2000::1/128\"\n  status = \"active\"\n  virtual_machine_interface_id = netbox_interface.test.id\n}\nresource \"netbox_primary_ip\" \"test_v6\" {\n  virtual_machine_id = netbox_virtual_machine.test.id\n  ip_address_id = netbox_ip_address.test_v6.id\n  ip_address_version = 6\n}`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_primary_ip.test_v6\", \"virtual_machine_id\", \"netbox_virtual_machine.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_primary_ip.test_v6\", \"ip_address_id\", \"netbox_ip_address.test_v6\", \"id\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"memory_mb\", \"1024\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"vcpus\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"disk_size_mb\", \"256\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"status\", \"planned\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rack.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxRackStatusOptions = []string{\"reserved\", \"available\", \"planned\", \"active\", \"deprecated\"}\nvar resourceNetboxRackWeightUnitOptions = []string{\"kg\", \"g\", \"lb\", \"oz\"}\nvar resourceNetboxRackOuterUnitOptions = []string{\"mm\", \"in\"}\nvar resourceNetboxRackWidthOptions = []int{10, 19, 21, 23}\nvar resourceNetboxRackFormFactorOptions = []string{\"2-post-frame\", \"4-post-frame\", \"4-post-cabinet\", \"wall-frame\", \"wall-frame-vertical\", \"wall-cabinet\", \"wall-cabinet-vertical\"}\n\nfunc resourceNetboxRack() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxRackCreate,\n\t\tRead:   resourceNetboxRackRead,\n\t\tUpdate: resourceNetboxRackUpdate,\n\t\tDelete: resourceNetboxRackDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/rack/):\n\n> The rack model represents a physical two- or four-post equipment rack in which devices can be installed. Each rack must be assigned to a site, and may optionally be assigned to a location within that site. Racks can also be organized by user-defined functional roles. The name and facility ID of each rack within a location must be unique.\n\nRack height is measured in rack units (U); racks are commonly between 42U and 48U tall, but NetBox allows you to define racks of arbitrary height. A toggle is provided to indicate whether rack units are in ascending (from the ground up) or descending order.\n\nEach rack is assigned a name and (optionally) a separate facility ID. This is helpful when leasing space in a data center your organization does not own: The facility will often assign a seemingly arbitrary ID to a rack (for example, \"M204.313\") whereas internally you refer to is simply as \"R113.\" A unique serial number and asset tag may also be associated with each rack.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackStatusOptions),\n\t\t\t},\n\t\t\t\"width\": {\n\t\t\t\tType: schema.TypeInt,\n\t\t\t\t//Required:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.IntInSlice(resourceNetboxRackWidthOptions),\n\t\t\t\tDescription:  \"Valid values are `10`, `19`, `21` and `23`\",\n\t\t\t},\n\t\t\t\"u_height\": {\n\t\t\t\tType: schema.TypeInt,\n\t\t\t\t//Required:     true,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.IntBetween(1, 100),\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"facility_id\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"location_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"serial\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 50),\n\t\t\t},\n\t\t\t\"asset_tag\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 50),\n\t\t\t},\n\t\t\t\"weight\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"max_weight\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validatePositiveInt32,\n\t\t\t},\n\t\t\t\"weight_unit\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"weight\", \"max_weight\"},\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackWeightUnitOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackWeightUnitOptions),\n\t\t\t},\n\t\t\t\"desc_units\": {\n\t\t\t\tType:        schema.TypeBool,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"If rack units are descending\",\n\t\t\t\tDefault:     false,\n\t\t\t},\n\t\t\t\"outer_width\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t},\n\t\t\t\"outer_depth\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t},\n\t\t\t\"outer_unit\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"outer_width\", \"outer_depth\"},\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackOuterUnitOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackOuterUnitOptions),\n\t\t\t},\n\t\t\t\"mounting_depth\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t\t\"form_factor\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackFormFactorOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackFormFactorOptions),\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxRackCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tsiteID := int64(d.Get(\"site_id\").(int))\n\tstatus := d.Get(\"status\").(string)\n\twidth := int64(d.Get(\"width\").(int))\n\tuHeight := int64(d.Get(\"u_height\").(int))\n\n\tdata := models.WritableRack{\n\t\tName:    &name,\n\t\tSite:    &siteID,\n\t\tStatus:  status,\n\t\tWidth:   width,\n\t\tUHeight: uHeight,\n\t}\n\n\tdata.Tenant = getOptionalInt(d, \"tenant_id\")\n\tif facilityID := getOptionalStr(d, \"facility_id\", false); facilityID != \"\" {\n\t\tdata.FacilityID = strToPtr(facilityID)\n\t}\n\tdata.Location = getOptionalInt(d, \"location_id\")\n\tdata.Role = getOptionalInt(d, \"role_id\")\n\tdata.Serial = getOptionalStr(d, \"serial\", false)\n\tif assetTag := getOptionalStr(d, \"asset_tag\", false); assetTag != \"\" {\n\t\tdata.AssetTag = &assetTag\n\t}\n\tdata.Weight = getOptionalFloat(d, \"weight\")\n\tdata.MaxWeight = getOptionalInt(d, \"max_weight\")\n\tdata.WeightUnit = getOptionalStr(d, \"weight_unit\", false)\n\n\tif descUnits, ok := d.GetOk(\"desc_units\"); ok {\n\t\tdata.DescUnits = descUnits.(bool)\n\t}\n\n\tdata.OuterWidth = getOptionalInt(d, \"outer_width\")\n\tdata.OuterDepth = getOptionalInt(d, \"outer_depth\")\n\tdata.OuterUnit = getOptionalStr(d, \"outer_unit\", false)\n\tdata.MountingDepth = getOptionalInt(d, \"mounting_depth\")\n\tdata.Description = getOptionalStr(d, \"description\", false)\n\tdata.Comments = getOptionalStr(d, \"comments\", false)\n\tdata.FormFactor = getOptionalStr(d, \"form_factor\", false)\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimRacksCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimRacksCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxRackRead(d, m)\n}\n\nfunc resourceNetboxRackRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRacksReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimRacksRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRacksReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\track := res.GetPayload()\n\n\td.Set(\"name\", rack.Name)\n\n\tif rack.Site != nil {\n\t\td.Set(\"site_id\", rack.Site.ID)\n\t} else {\n\t\td.Set(\"site_id\", nil)\n\t}\n\n\tif rack.Status != nil {\n\t\td.Set(\"status\", rack.Status.Value)\n\t} else {\n\t\td.Set(\"status\", nil)\n\t}\n\n\tif rack.Width != nil {\n\t\td.Set(\"width\", rack.Width.Value)\n\t} else {\n\t\td.Set(\"width\", nil)\n\t}\n\n\td.Set(\"u_height\", rack.UHeight)\n\n\tif rack.Tenant != nil {\n\t\td.Set(\"tenant_id\", rack.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\td.Set(\"facility_id\", rack.FacilityID)\n\n\tif rack.Location != nil {\n\t\td.Set(\"location_id\", rack.Location.ID)\n\t} else {\n\t\td.Set(\"location_id\", nil)\n\t}\n\n\tif rack.Role != nil {\n\t\td.Set(\"role_id\", rack.Role.ID)\n\t} else {\n\t\td.Set(\"role_id\", nil)\n\t}\n\n\td.Set(\"serial\", rack.Serial)\n\td.Set(\"asset_tag\", rack.AssetTag)\n\n\td.Set(\"weight\", rack.Weight)\n\td.Set(\"max_weight\", rack.MaxWeight)\n\n\tif rack.WeightUnit != nil {\n\t\td.Set(\"weight_unit\", rack.WeightUnit.Value)\n\t} else {\n\t\td.Set(\"weight_unit\", nil)\n\t}\n\n\td.Set(\"desc_units\", rack.DescUnits)\n\td.Set(\"outer_width\", rack.OuterWidth)\n\td.Set(\"outer_depth\", rack.OuterDepth)\n\n\tif rack.OuterUnit != nil {\n\t\td.Set(\"outer_unit\", rack.OuterUnit.Value)\n\t} else {\n\t\td.Set(\"outer_unit\", nil)\n\t}\n\n\td.Set(\"mounting_depth\", rack.MountingDepth)\n\td.Set(\"description\", rack.Description)\n\td.Set(\"comments\", rack.Comments)\n\n\tif rack.FormFactor != nil {\n\t\td.Set(\"form_factor\", rack.FormFactor.Value)\n\t} else {\n\t\td.Set(\"form_factor\", nil)\n\t}\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxRackUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tname := d.Get(\"name\").(string)\n\tsiteID := int64(d.Get(\"site_id\").(int))\n\tstatus := d.Get(\"status\").(string)\n\twidth := int64(d.Get(\"width\").(int))\n\tuHeight := int64(d.Get(\"u_height\").(int))\n\n\tdata := models.WritableRack{\n\t\tName:    &name,\n\t\tSite:    &siteID,\n\t\tStatus:  status,\n\t\tWidth:   width,\n\t\tUHeight: uHeight,\n\t}\n\n\tdata.Tenant = getOptionalInt(d, \"tenant_id\")\n\n\tif facilityID := getOptionalStr(d, \"facility_id\", false); facilityID != \"\" {\n\t\tdata.FacilityID = strToPtr(facilityID)\n\t}\n\n\tdata.Location = getOptionalInt(d, \"location_id\")\n\tdata.Role = getOptionalInt(d, \"role_id\")\n\tdata.Serial = getOptionalStr(d, \"serial\", true)\n\tif assetTag := getOptionalStr(d, \"asset_tag\", false); assetTag != \"\" {\n\t\tdata.AssetTag = &assetTag\n\t}\n\tdata.Weight = getOptionalFloat(d, \"weight\")\n\tdata.MaxWeight = getOptionalInt(d, \"max_weight\")\n\tdata.WeightUnit = getOptionalStr(d, \"weight_unit\", false)\n\n\tif descUnits, ok := d.GetOk(\"desc_units\"); ok {\n\t\tdata.DescUnits = descUnits.(bool)\n\t}\n\n\tdata.OuterWidth = getOptionalInt(d, \"outer_width\")\n\tdata.OuterDepth = getOptionalInt(d, \"outer_depth\")\n\tdata.OuterUnit = getOptionalStr(d, \"outer_unit\", false)\n\tdata.MountingDepth = getOptionalInt(d, \"mounting_depth\")\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.Comments = getOptionalStr(d, \"comments\", true)\n\tdata.FormFactor = getOptionalStr(d, \"form_factor\", false)\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := dcim.NewDcimRacksPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimRacksPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxRackRead(d, m)\n}\n\nfunc resourceNetboxRackDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRacksDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimRacksDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRacksDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rack_reservation.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxRackReservation() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxRackReservationCreate,\n\t\tRead:   resourceNetboxRackReservationRead,\n\t\tUpdate: resourceNetboxRackReservationUpdate,\n\t\tDelete: resourceNetboxRackReservationDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/rackreservation/):\n\n> Users can reserve specific units within a rack for future use. An arbitrary set of units within a rack can be associated with a single reservation, but reservations cannot span multiple racks. A description is required for each reservation, reservations may optionally be associated with a specific tenant.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"rack_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"units\": {\n\t\t\t\tType: schema.TypeSet,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t\tRequired: true,\n\t\t\t\tSet:      schema.HashInt,\n\t\t\t},\n\t\t\t\"user_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxRackReservationCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tparams := dcim.NewDcimRackReservationsCreateParams().WithData(\n\t\t&models.WritableRackReservation{\n\t\t\tRack:        getOptionalInt(d, \"rack_id\"),\n\t\t\tUnits:       toInt64PtrList(d.Get(\"units\")),\n\t\t\tUser:        getOptionalInt(d, \"user_id\"),\n\t\t\tDescription: strToPtr(getOptionalStr(d, \"description\", false)),\n\t\t\tTenant:      getOptionalInt(d, \"tenant_id\"),\n\t\t\tComments:    getOptionalStr(d, \"comments\", false),\n\t\t\tTags:        tags,\n\t\t},\n\t)\n\n\tres, err := api.Dcim.DcimRackReservationsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxRackReservationRead(d, m)\n}\n\nfunc resourceNetboxRackReservationRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRackReservationsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimRackReservationsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRackReservationsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\trackRes := res.GetPayload()\n\n\tif rackRes.Rack != nil {\n\t\td.Set(\"rack_id\", rackRes.Rack.ID)\n\t}\n\n\tunits := []int{}\n\tfor _, unit := range rackRes.Units {\n\t\tunits = append(units, int(*unit))\n\t}\n\td.Set(\"units\", units)\n\n\tif rackRes.User != nil {\n\t\td.Set(\"user_id\", rackRes.User.ID)\n\t}\n\n\td.Set(\"description\", rackRes.Description)\n\n\tif rackRes.Tenant != nil {\n\t\td.Set(\"tenant_id\", rackRes.Tenant.ID)\n\t}\n\n\td.Set(\"comments\", rackRes.Comments)\n\n\tapi.readTags(d, res.GetPayload().Tags)\n\treturn nil\n}\n\nfunc resourceNetboxRackReservationUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tdata := models.WritableRackReservation{\n\t\tRack:        getOptionalInt(d, \"rack_id\"),\n\t\tUnits:       toInt64PtrList(d.Get(\"units\")),\n\t\tUser:        getOptionalInt(d, \"user_id\"),\n\t\tDescription: strToPtr(getOptionalStr(d, \"description\", false)),\n\t\tTenant:      getOptionalInt(d, \"tenant_id\"),\n\t\tComments:    getOptionalStr(d, \"comments\", false),\n\t\tTags:        tags,\n\t}\n\n\tparams := dcim.NewDcimRackReservationsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Dcim.DcimRackReservationsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxRackReservationRead(d, m)\n}\n\nfunc resourceNetboxRackReservationDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRackReservationsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimRackReservationsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRackReservationsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rack_reservation_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxRackReservationFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_rack\" \"test\" {\n   name     = \"%[1]s\"\n   site_id  = netbox_site.test.id\n   status   = \"active\"\n   width    = 10\n   u_height = 40\n}`, testName)\n}\n\nfunc TestAccNetboxRackReservation_basic(t *testing.T) {\n\ttestSlug := \"rack_reservation_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxRackReservationFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_rack_reservation\" \"test\" {\n  rack_id = netbox_rack.test.id\n  units = [1,2,3,4,5]\n  user_id = 1\n  description = \"%[1]sdescription\"\n  tenant_id = netbox_tenant.test.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack_reservation.test\", \"rack_id\", \"netbox_rack.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack_reservation.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_reservation.test\", \"units.#\", \"5\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_reservation.test\", \"user_id\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_reservation.test\", \"description\", testName+\"description\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_rack_reservation.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_rack_reservation\", &resource.Sweeper{\n\t\tName:         \"netbox_rack_reservation\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimRackReservationsListParams()\n\t\t\tres, err := api.Dcim.DcimRackReservationsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, rackRes := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*rackRes.Description, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimRackReservationsDeleteParams().WithID(rackRes.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimRackReservationsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a rack_reservation\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rack_role.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxRackRole() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxRackRoleCreate,\n\t\tRead:   resourceNetboxRackRoleRead,\n\t\tUpdate: resourceNetboxRackRoleUpdate,\n\t\tDelete: resourceNetboxRackRoleDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/models/dcim/rackrole/):\n\n> Each rack can optionally be assigned a user-defined functional role. For example, you might designate a rack for compute or storage resources, or to house colocated customer devices.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxRackRoleCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tcolor := d.Get(\"color_hex\").(string)\n\tdescription := getOptionalStr(d, \"description\", false)\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tparams := dcim.NewDcimRackRolesCreateParams().WithData(\n\t\t&models.RackRole{\n\t\t\tName:        &name,\n\t\t\tSlug:        &slug,\n\t\t\tColor:       color,\n\t\t\tDescription: description,\n\t\t\tTags:        tags,\n\t\t},\n\t)\n\n\tres, err := api.Dcim.DcimRackRolesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxRackRoleRead(d, m)\n}\n\nfunc resourceNetboxRackRoleRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRackRolesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimRackRolesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRackRolesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\trackRole := res.GetPayload()\n\n\td.Set(\"name\", rackRole.Name)\n\td.Set(\"slug\", rackRole.Slug)\n\td.Set(\"description\", rackRole.Description)\n\td.Set(\"color_hex\", rackRole.Color)\n\tapi.readTags(d, res.GetPayload().Tags)\n\treturn nil\n}\n\nfunc resourceNetboxRackRoleUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.RackRole{}\n\n\tname := d.Get(\"name\").(string)\n\tcolor := d.Get(\"color_hex\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.Color = color\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tparams := dcim.NewDcimRackRolesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Dcim.DcimRackRolesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxRackRoleRead(d, m)\n}\n\nfunc resourceNetboxRackRoleDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRackRolesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimRackRolesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRackRolesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rack_role_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxRackRole_basic(t *testing.T) {\n\ttestSlug := \"rack_role_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_rack_role\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n  color_hex = \"111111\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_role.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_role.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_role.test\", \"color_hex\", \"111111\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_rack_role.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxRackRole_defaultSlug(t *testing.T) {\n\ttestSlug := \"rack_role_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_rack_role\" \"test\" {\n  name = \"%s\"\n  color_hex = \"111111\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_role.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_role.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_rack_role\", &resource.Sweeper{\n\t\tName:         \"netbox_rack_role\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimRackRolesListParams()\n\t\t\tres, err := api.Dcim.DcimRackRolesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, rackRole := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*rackRole.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimRackRolesDeleteParams().WithID(rackRole.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimRackRolesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a rack_role\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rack_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc testAccNetboxRackFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_location\" \"test\" {\n  name = \"%[1]s\"\n  site_id =netbox_site.test.id\n}\n\nresource \"netbox_rack_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}`, testName)\n}\n\nfunc TestAccNetboxRack_basic(t *testing.T) {\n\ttestSlug := \"rack_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckRackDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxRackFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_rack\" \"test\" {\n  name        = \"%[1]s\"\n  site_id     = netbox_site.test.id\n  status      = \"reserved\"\n  width       = 19\n  u_height    = 48\n  tags        = [netbox_tag.test_a.name]\n  tenant_id   = netbox_tenant.test.id\n  facility_id = \"%[1]sfacility\"\n  location_id = netbox_location.test.id\n  role_id     = netbox_rack_role.test.id\n  serial      = \"%[1]sserial\"\n  asset_tag   = \"%[1]sasset_tag\"\n  desc_units  = true\n  outer_width = 10\n  outer_depth = 15\n  outer_unit  = \"mm\"\n  comments    = \"%[1]scomments\"\n  form_factor = \"2-post-frame\"\n}\n\nresource \"netbox_rack\" \"test2\" {\n  name        = \"%[1]s2\"\n  site_id     = netbox_site.test.id\n  location_id = netbox_location.test.id\n  status      = \"reserved\"\n  width       = 19\n  u_height    = 48\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"status\", \"reserved\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"width\", \"19\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"u_height\", \"48\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"facility_id\", testName+\"facility\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack.test\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack.test\", \"role_id\", \"netbox_rack_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"serial\", testName+\"serial\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"asset_tag\", testName+\"asset_tag\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"desc_units\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"outer_width\", \"10\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"outer_depth\", \"15\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"outer_unit\", \"mm\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"comments\", testName+\"comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"form_factor\", \"2-post-frame\"),\n\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test2\", \"name\", testName+\"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack.test2\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack.test2\", \"location_id\", \"netbox_location.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test2\", \"status\", \"reserved\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test2\", \"width\", \"19\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test2\", \"u_height\", \"48\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxRackFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_rack\" \"test\" {\n  name     = \"%[1]s\"\n  site_id  = netbox_site.test.id\n  status   = \"reserved\"\n  width    = 19\n  u_height = 48\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"status\", \"reserved\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"width\", \"19\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"u_height\", \"48\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"tenant_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"facility_id\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"location_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"role_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"serial\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"asset_tag\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"weight\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"max_weight\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"weight_unit\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"desc_units\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"outer_width\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"outer_depth\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"outer_unit\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"mounting_depth\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"form_factor\", \"\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_rack.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\n/*\nNot sure if creating a rack from rack type is a sustainable process when using terraform\nfunc TestAccNetboxRack_fromRackType(t *testing.T) {\n\ttestSlug := \"rack_fromType\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckRackDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_rack_type\" \"test\" {\n  model             = \"%[1]s\"\n  manufacturer_id   = netbox_manufacturer.test.id\n  width             = 19\n  u_height          = 48\n  starting_unit     = 1\n  form_factor       = \"2-post-frame\"\n}\n\nresource \"netbox_rack\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  status = \"active\"\n  comments = \"%[1]scomments\"\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"width\", \"19\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"u_height\", \"48\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack.test\", \"tags.#\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_rack.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n*/\n\nfunc testAccCheckRackDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each rack\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_rack\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our rack by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimRacksReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimRacksRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"rack (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimRacksReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_rack\", &resource.Sweeper{\n\t\tName:         \"netbox_rack\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimRacksListParams()\n\t\t\tres, err := api.Dcim.DcimRacksList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, Rack := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*Rack.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimRacksDeleteParams().WithID(Rack.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimRacksDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a rack\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rack_type.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxRackTypeFormFactorOptions = []string{\"2-post-frame\", \"4-post-frame\", \"4-post-cabinet\", \"wall-frame\", \"wall-frame-vertical\", \"wall-cabinet\", \"wall-cabinet-vertical\"}\nvar resourceNetboxRackTypeWeightUnitOptions = []string{\"kg\", \"g\", \"lb\", \"oz\"}\nvar resourceNetboxRackTypeOuterUnitOptions = []string{\"mm\", \"in\"}\nvar resourceNetboxRackTypeWidthOptions = []int{10, 19, 21, 23}\n\nfunc resourceNetboxRackType() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxRackTypeCreate,\n\t\tRead:   resourceNetboxRackTypeRead,\n\t\tUpdate: resourceNetboxRackTypeUpdate,\n\t\tDelete: resourceNetboxRackTypeDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://netboxlabs.com/docs/netbox/en/stable/models/dcim/racktype/):\n\n> A rack type defines the physical characteristics of a particular model of rack.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"model\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"manufacturer_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"form_factor\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackTypeFormFactorOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackTypeFormFactorOptions),\n\t\t\t},\n\t\t\t\"width\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.IntInSlice(resourceNetboxRackTypeWidthOptions),\n\t\t\t\tDescription:  \"Valid values are `10`, `19`, `21` and `23`\",\n\t\t\t},\n\t\t\t\"u_height\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.IntBetween(1, 100),\n\t\t\t},\n\t\t\t\"starting_unit\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"description\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t},\n\t\t\t\"outer_width\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t},\n\t\t\t\"outer_depth\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t},\n\t\t\t\"outer_unit\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"outer_width\", \"outer_depth\"},\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackTypeOuterUnitOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackTypeOuterUnitOptions),\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"weight\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"max_weight\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validatePositiveInt32,\n\t\t\t},\n\t\t\t\"weight_unit\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"weight\", \"max_weight\"},\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackTypeWeightUnitOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackTypeWeightUnitOptions),\n\t\t\t},\n\t\t\t\"mounting_depth_mm\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t},\n\t\t\t//\t\t\t\"tenant_id\": {\n\t\t\t//\t\t\t\tType:     schema.TypeInt,\n\t\t\t//\t\t\t\tOptional: true,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"facility_id\": {\n\t\t\t//\t\t\t\tType:     schema.TypeString,\n\t\t\t//\t\t\t\tOptional: true,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"location_id\": {\n\t\t\t//\t\t\t\tType:     schema.TypeInt,\n\t\t\t//\t\t\t\tOptional: true,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"role_id\": {\n\t\t\t//\t\t\t\tType:     schema.TypeInt,\n\t\t\t//\t\t\t\tOptional: true,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"serial\": {\n\t\t\t//\t\t\t\tType:         schema.TypeString,\n\t\t\t//\t\t\t\tOptional:     true,\n\t\t\t//\t\t\t\tValidateFunc: validation.StringLenBetween(0, 50),\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"asset_tag\": {\n\t\t\t//\t\t\t\tType:         schema.TypeString,\n\t\t\t//\t\t\t\tOptional:     true,\n\t\t\t//\t\t\t\tValidateFunc: validation.StringLenBetween(0, 50),\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"type\": {\n\t\t\t//\t\t\t\tType:         schema.TypeString,\n\t\t\t//\t\t\t\tOptional:     true,\n\t\t\t//\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackTypeTypeOptions, false),\n\t\t\t//\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackTypeTypeOptions),\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"desc_units\": {\n\t\t\t//\t\t\t\tType:        schema.TypeBool,\n\t\t\t//\t\t\t\tOptional:    true,\n\t\t\t//\t\t\t\tDescription: \"If rack units are descending\",\n\t\t\t//\t\t\t\tDefault:     false,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"outer_width\": {\n\t\t\t//\t\t\t\tType:         schema.TypeInt,\n\t\t\t//\t\t\t\tOptional:     true,\n\t\t\t//\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"outer_depth\": {\n\t\t\t//\t\t\t\tType:         schema.TypeInt,\n\t\t\t//\t\t\t\tOptional:     true,\n\t\t\t//\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"outer_unit\": {\n\t\t\t//\t\t\t\tType:         schema.TypeString,\n\t\t\t//\t\t\t\tOptional:     true,\n\t\t\t//\t\t\t\tRequiredWith: []string{\"outer_width\", \"outer_depth\"},\n\t\t\t//\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxRackTypeOuterUnitOptions, false),\n\t\t\t//\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxRackTypeOuterUnitOptions),\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"mounting_depth\": {\n\t\t\t//\t\t\t\tType:         schema.TypeInt,\n\t\t\t//\t\t\t\tOptional:     true,\n\t\t\t//\t\t\t\tValidateFunc: validatePositiveInt16,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"description\": {\n\t\t\t//\t\t\t\tType:         schema.TypeString,\n\t\t\t//\t\t\t\tOptional:     true,\n\t\t\t//\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\t\"comments\": {\n\t\t\t//\t\t\t\tType:     schema.TypeString,\n\t\t\t//\t\t\t\tOptional: true,\n\t\t\t//\t\t\t},\n\t\t\t//\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxRackTypeCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tmodel := d.Get(\"model\").(string)\n\tformFactor := d.Get(\"form_factor\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(model)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\tmanufacturerID := int64(d.Get(\"manufacturer_id\").(int))\n\twidth := int64(d.Get(\"width\").(int))\n\tuHeight := int64(d.Get(\"u_height\").(int))\n\n\tdata := models.WritableRackTypeRequest{\n\t\tModel:         &model,\n\t\tFormFactor:    &formFactor,\n\t\tSlug:          &slug,\n\t\tManufacturer:  &manufacturerID,\n\t\tWidth:         &width,\n\t\tUHeight:       uHeight,\n\t\tDescription:   getOptionalStr(d, \"description\", false),\n\t\tOuterWidth:    getOptionalInt(d, \"outer_width\"),\n\t\tOuterDepth:    getOptionalInt(d, \"outer_depth\"),\n\t\tOuterUnit:     getOptionalStr(d, \"outer_unit\", false),\n\t\tComments:      getOptionalStr(d, \"comments\", false),\n\t\tWeight:        getOptionalFloat(d, \"weight\"),\n\t\tMaxWeight:     getOptionalInt(d, \"max_weight\"),\n\t\tWeightUnit:    getOptionalStr(d, \"weight_unit\", false),\n\t\tMountingDepth: getOptionalInt(d, \"mounting_depth_mm\"),\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := dcim.NewDcimRackTypesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimRackTypesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxRackTypeRead(d, m)\n}\n\nfunc resourceNetboxRackTypeRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRackTypesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimRackTypesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRackTypesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\trackType := res.GetPayload()\n\n\td.Set(\"model\", rackType.Model)\n\td.Set(\"form_factor\", rackType.FormFactor.Value)\n\td.Set(\"starting_unit\", rackType.StartingUnit)\n\td.Set(\"manufacturer_id\", rackType.Manufacturer.ID)\n\n\tif rackType.Width != nil {\n\t\td.Set(\"width\", rackType.Width.Value)\n\t} else {\n\t\td.Set(\"width\", nil)\n\t}\n\n\td.Set(\"u_height\", rackType.UHeight)\n\tapi.readTags(d, res.GetPayload().Tags)\n\td.Set(\"description\", rackType.Description)\n\td.Set(\"comments\", rackType.Comments)\n\n\td.Set(\"outer_width\", rackType.OuterWidth)\n\td.Set(\"outer_depth\", rackType.OuterDepth)\n\n\tif rackType.OuterUnit != nil {\n\t\td.Set(\"outer_unit\", rackType.OuterUnit.Value)\n\t} else {\n\t\td.Set(\"outer_unit\", nil)\n\t}\n\n\td.Set(\"weight\", rackType.Weight)\n\td.Set(\"max_weight\", rackType.MaxWeight)\n\n\tif rackType.WeightUnit != nil {\n\t\td.Set(\"weight_unit\", rackType.WeightUnit.Value)\n\t} else {\n\t\td.Set(\"weight_unit\", nil)\n\t}\n\n\td.Set(\"mounting_depth_mm\", rackType.MountingDepth)\n\n\treturn nil\n}\n\nfunc resourceNetboxRackTypeUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tmodel := d.Get(\"model\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(model)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\tmanufacturerID := int64(d.Get(\"manufacturer_id\").(int))\n\twidth := int64(d.Get(\"width\").(int))\n\tuHeight := int64(d.Get(\"u_height\").(int))\n\n\tdata := models.WritableRackTypeRequest{\n\t\tModel:         &model,\n\t\tSlug:          &slug,\n\t\tManufacturer:  &manufacturerID,\n\t\tWidth:         &width,\n\t\tUHeight:       uHeight,\n\t\tDescription:   getOptionalStr(d, \"description\", true),\n\t\tOuterWidth:    getOptionalInt(d, \"outer_width\"),\n\t\tOuterDepth:    getOptionalInt(d, \"outer_depth\"),\n\t\tOuterUnit:     getOptionalStr(d, \"outer_unit\", true),\n\t\tComments:      getOptionalStr(d, \"comments\", true),\n\t\tWeight:        getOptionalFloat(d, \"weight\"),\n\t\tMaxWeight:     getOptionalInt(d, \"max_weight\"),\n\t\tWeightUnit:    getOptionalStr(d, \"weight_unit\", true),\n\t\tMountingDepth: getOptionalInt(d, \"mounting_depth_mm\"),\n\t}\n\n\tparams := dcim.NewDcimRackTypesUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Dcim.DcimRackTypesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxRackTypeRead(d, m)\n}\n\nfunc resourceNetboxRackTypeDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRackTypesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimRackTypesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRackTypesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rack_type_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc testAccNetboxRackTypeFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}`, testName)\n}\n\nfunc TestAccNetboxRackType_basic(t *testing.T) {\n\ttestSlug := \"racktype_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckRackTypeDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxRackTypeFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_rack_type\" \"test\" {\n  model             = \"%[1]s\"\n  manufacturer_id   = netbox_manufacturer.test.id\n  width             = 19\n  u_height          = 48\n  starting_unit     = 1\n  form_factor       = \"2-post-frame\"\n  tags              = [netbox_tag.test_a.name]\n  description       = \"%[1]s\"\n  outer_width       = 10\n  outer_depth       = 15\n  outer_unit        = \"mm\"\n  weight            = 15\n  max_weight        = 20\n  weight_unit       = \"kg\"\n  mounting_depth_mm = 21\n  comments          = \"%[1]scomments\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"model\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"description\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_rack_type.test\", \"manufacturer_id\", \"netbox_manufacturer.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"width\", \"19\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"u_height\", \"48\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"outer_width\", \"10\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"outer_depth\", \"15\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"outer_unit\", \"mm\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"weight\", \"15\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"max_weight\", \"20\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"weight_unit\", \"kg\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"comments\", testName+\"comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rack_type.test\", \"mounting_depth_mm\", \"21\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_rack_type.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckRackTypeDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each rack\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_rack_type\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our rack by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimRackTypesReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimRackTypesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"rack type (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimRackTypesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_rack_type\", &resource.Sweeper{\n\t\tName:         \"netbox_rack_type\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimRackTypesListParams()\n\t\t\tres, err := api.Dcim.DcimRackTypesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, RackType := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*RackType.Model, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimRackTypesDeleteParams().WithID(RackType.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimRackTypesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a rack type\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_region.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxRegion() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxRegionCreate,\n\t\tRead:   resourceNetboxRegionRead,\n\t\tUpdate: resourceNetboxRegionUpdate,\n\t\tDelete: resourceNetboxRegionDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#regions):\n\n> Sites can be arranged geographically using regions. A region might represent a continent, country, city, campus, or other area depending on your use case. Regions can be nested recursively to construct a hierarchy. For example, you might define several country regions, and within each of those several state or city regions to which sites are assigned.\n>\n> Each region must have a name that is unique within its parent region, if any.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"parent_region_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t},\n\t\t\t\"id\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxRegionCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableRegion{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tif description, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = description.(string)\n\t}\n\n\tparentRegionIDValue, ok := d.GetOk(\"parent_region_id\")\n\tif ok {\n\t\tdata.Parent = int64ToPtr(int64(parentRegionIDValue.(int)))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := dcim.NewDcimRegionsCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimRegionsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxRegionRead(d, m)\n}\n\nfunc resourceNetboxRegionRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRegionsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimRegionsRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRegionsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\tif res.GetPayload().Parent != nil {\n\t\td.Set(\"parent_region_id\", res.GetPayload().Parent.ID)\n\t} else {\n\t\td.Set(\"parent_region_id\", nil)\n\t}\n\td.Set(\"description\", res.GetPayload().Description)\n\treturn nil\n}\n\nfunc resourceNetboxRegionUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableRegion{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tif description, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = description.(string)\n\t}\n\n\tparentRegionIDValue, ok := d.GetOk(\"parent_region_id\")\n\tif ok {\n\t\tdata.Parent = int64ToPtr(int64(parentRegionIDValue.(int)))\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := dcim.NewDcimRegionsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Dcim.DcimRegionsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxRegionRead(d, m)\n}\n\nfunc resourceNetboxRegionDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimRegionsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimRegionsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimRegionsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_region_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxRegion_basic(t *testing.T) {\n\ttestSlug := \"region_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_region\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n  description = \"%[1]s\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_region.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_region.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_region.test\", \"parent_region_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_region.test\", \"description\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_region.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxRegion_defaultSlug(t *testing.T) {\n\ttestSlug := \"region_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_region\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_region.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_region.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_region\", &resource.Sweeper{\n\t\tName:         \"netbox_region\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimRegionsListParams()\n\t\t\tres, err := api.Dcim.DcimRegionsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, region := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*region.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimRegionsDeleteParams().WithID(region.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimRegionsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a Region\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rir.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxRir() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxRirCreate,\n\t\tRead:   resourceNetboxRirRead,\n\t\tUpdate: resourceNetboxRirUpdate,\n\t\tDelete: resourceNetboxRirDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs):\n\n> Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which \"owns\" certain address space. There also exist lower-tier registries which serve particular geographic areas.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"is_private\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  false,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxRirCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.RIR{}\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Name = &name\n\tdata.Slug = &slug\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.Tags = []*models.NestedTag{}\n\tdata.IsPrivate = d.Get(\"is_private\").(bool)\n\n\tparams := ipam.NewIpamRirsCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamRirsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxRirUpdate(d, m)\n}\n\nfunc resourceNetboxRirRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamRirsReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamRirsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamRirsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\trir := res.GetPayload()\n\n\td.Set(\"name\", rir.Name)\n\td.Set(\"slug\", rir.Slug)\n\td.Set(\"description\", rir.Description)\n\td.Set(\"is_private\", rir.IsPrivate)\n\n\treturn nil\n}\n\nfunc resourceNetboxRirUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.RIR{}\n\n\tname := d.Get(\"name\").(string)\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Name = &name\n\tdata.Slug = &slug\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.Tags = []*models.NestedTag{}\n\tdata.IsPrivate = d.Get(\"is_private\").(bool)\n\n\tparams := ipam.NewIpamRirsUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Ipam.IpamRirsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxRirRead(d, m)\n}\n\nfunc resourceNetboxRirDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamRirsDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamRirsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamRirsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_rir_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxRir_basic(t *testing.T) {\n\ttestSlug := \"rir\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_rir\" \"test_basic\" {\n  name        = \"%s\"\n  slug        = \"%s\"\n  description = \"my-description\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_basic\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_basic\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_basic\", \"description\", \"my-description\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_rir.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxRir_privacy(t *testing.T) {\n\ttestSlug := \"rir_privacy\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_rir\" \"test_privacy\" {\n  name        = \"%s\"\n  slug        = \"%s\"\n  is_private  = false\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"is_private\", \"false\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_rir\" \"test_privacy\" {\n  name        = \"%s\"\n  slug        = \"%s\"\n  is_private  = true\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"is_private\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_rir\" \"test_privacy\" {\n  name        = \"%s\"\n  slug        = \"%s\"\n  is_private  = false\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_rir.test_privacy\", \"is_private\", \"false\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_rir\", &resource.Sweeper{\n\t\tName:         \"netbox_rir\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamRirsListParams()\n\t\t\tres, err := api.Ipam.IpamRirsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, role := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*role.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamRirsDeleteParams().WithID(role.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamRirsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a rir\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_route_target.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxRouteTarget() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxRouteTargetCreate,\n\t\tRead:   resourceNetboxRouteTargetRead,\n\t\tUpdate: resourceNetboxRouteTargetUpdate,\n\t\tDelete: resourceNetboxRouteTargetDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/models/ipam/routetarget/):\n\n> A route target is a particular type of extended BGP community used to control the redistribution of routes among VRF tables in a network. Route targets can be assigned to individual VRFs in NetBox as import or export targets (or both) to model this exchange in an L3VPN. Each route target must be given a unique name, which should be in a format prescribed by RFC 4364, similar to a VR route distinguisher.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 21),\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\nfunc resourceNetboxRouteTargetCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableRouteTarget{}\n\n\tname := d.Get(\"name\").(string)\n\n\tdata.Name = &name\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := ipam.NewIpamRouteTargetsCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamRouteTargetsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxRouteTargetUpdate(d, m)\n}\n\nfunc resourceNetboxRouteTargetRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamRouteTargetsReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamRouteTargetsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamRouteTargetsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tif res.GetPayload().Name != nil {\n\t\td.Set(\"name\", res.GetPayload().Name)\n\t}\n\n\tif res.GetPayload().Tenant != nil {\n\t\td.Set(\"tenant_id\", res.GetPayload().Tenant.ID)\n\t}\n\n\tif res.GetPayload().Description != \"\" {\n\t\td.Set(\"description\", res.GetPayload().Description)\n\t}\n\n\tif res.GetPayload().Tags != nil {\n\t\tapi.readTags(d, res.GetPayload().Tags)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxRouteTargetUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableRouteTarget{}\n\n\tname := d.Get(\"name\").(string)\n\ttenantID := int64(d.Get(\"tenant_id\").(int))\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Name = &name\n\tdata.Description = description\n\tdata.Tenant = &tenantID\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := ipam.NewIpamRouteTargetsUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Ipam.IpamRouteTargetsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxRouteTargetRead(d, m)\n}\n\nfunc resourceNetboxRouteTargetDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamRouteTargetsDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamRouteTargetsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamRouteTargetsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_route_target_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc getNetboxRouteTargetResource(rtName, tenantName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"rt_acctest_basic\" {\n  name = \"%[2]s\"\n}\nresource \"netbox_route_target\" \"rt_acctest_basic\" {\n  name = \"%[1]s\"\n  description = \"rt for acctest\"\n  tenant_id = netbox_tenant.rt_acctest_basic.id\n}`, rtName, tenantName)\n}\n\nfunc Test_resourceNetboxRouteTarget(t *testing.T) {\n\ttestSlug := \"rt\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\n\t\t\t\tConfig: getNetboxRouteTargetResource(testName, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_route_target.rt_acctest_basic\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_route_target.rt_acctest_basic\", \"description\", \"rt for acctest\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_route_target.rt_acctest_basic\", \"tenant_id\", \"netbox_tenant.rt_acctest_basic\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_route_target.rt_acctest_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\t\t\tresource \"netbox_tenant\" \"rt_acctest_basic\" {\n\t\t\t\tname = \"%[2]s\"\n\t\t\t}\n\t\t\tresource \"netbox_route_target\" \"rt_acctest_basic\" {\n\t\t\t\tname = \"%[1]s\"\n\t\t\t\tdescription = \"change description\"\n\t\t\t\ttenant_id = netbox_tenant.rt_acctest_basic.id\n\t\t\t}`, testName, fmt.Sprintf(\"new%s\", testName)),\n\t\t\t\tCheck: resource.ComposeAggregateTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_route_target.rt_acctest_basic\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_route_target.rt_acctest_basic\", \"description\", \"change description\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_route_target.rt_acctest_basic\", \"tenant_id\", \"netbox_tenant.rt_acctest_basic\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_route_target.rt_acctest_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\n\t\t\tresource \"netbox_route_target\" \"rt_acctest_basic2\" {\n\t\t\t\tname = \"%[1]s\"\n\t\t\t\tdescription = \"change description\"\n\t\t\t\ttenant_id = \"10001\"\n\t\t\t}`, fmt.Sprintf(\"2%s\", testName)),\n\n\t\t\t\tExpectError: regexp.MustCompile(`.*Related object not found using the provided numeric ID.*`),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_route_target\", &resource.Sweeper{\n\t\tName:         \"netbox_route_target\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamRouteTargetsListParams()\n\t\t\tres, err := api.Ipam.IpamRouteTargetsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, role := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*role.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamRouteTargetsDeleteParams().WithID(role.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamRouteTargetsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a rir\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_service.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxServiceProtocolOptions = []string{\"tcp\", \"udp\", \"sctp\"}\n\nfunc resourceNetboxService() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxServiceCreate,\n\t\tRead:   resourceNetboxServiceRead,\n\t\tUpdate: resourceNetboxServiceUpdate,\n\t\tDelete: resourceNetboxServiceDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/services/#services):\n\n> A service represents a layer four TCP or UDP service available on a device or virtual machine. For example, you might want to document that an HTTP service is running on a device. Each service includes a name, protocol, and port number; for example, \"SSH (TCP/22)\" or \"DNS (UDP/53).\"\n>\n> A service may optionally be bound to one or more specific IP addresses belonging to its parent device or VM. (If no IP addresses are bound, the service is assumed to be reachable via any assigned IP address.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"virtual_machine_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"virtual_machine_id\", \"device_id\"},\n\t\t\t},\n\t\t\t\"protocol\": {\n\t\t\t\tType:             schema.TypeString,\n\t\t\t\tRequired:         true,\n\t\t\t\tValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(resourceNetboxServiceProtocolOptions, false)),\n\t\t\t\tDescription:      buildValidValueDescription(resourceNetboxServiceProtocolOptions),\n\t\t\t},\n\t\t\t\"port\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"port\", \"ports\"},\n\t\t\t\tDeprecated:   \"This field is deprecated. Please use the new \\\"ports\\\" attribute instead.\",\n\t\t\t},\n\t\t\t\"ports\": {\n\t\t\t\tType:         schema.TypeSet,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"port\", \"ports\"},\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tags\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeString,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"device_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"virtual_machine_id\", \"device_id\"},\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxServiceCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableService{}\n\n\tdataName := d.Get(\"name\").(string)\n\tdata.Name = &dataName\n\n\tdataProtocol := d.Get(\"protocol\").(string)\n\tdata.Protocol = &dataProtocol\n\n\t// for backwards compatibility, we allow either port or ports\n\t// the API only supports ports. We give precedence to port, if it exists.\n\tdataPort, dataPortOk := d.GetOk(\"port\")\n\tif dataPortOk {\n\t\tdata.Ports = []int64{int64(dataPort.(int))}\n\t} else {\n\t\t// if port is not set, ports has to be set\n\t\tvar dataPorts []int64\n\t\tif v := d.Get(\"ports\").(*schema.Set); v.Len() > 0 {\n\t\t\tfor _, v := range v.List() {\n\t\t\t\tdataPorts = append(dataPorts, int64(v.(int)))\n\t\t\t}\n\t\t\tdata.Ports = dataPorts\n\t\t}\n\t}\n\n\tvirtualMachineID := getOptionalInt(d, \"virtual_machine_id\")\n\tdeviceID := getOptionalInt(d, \"device_id\")\n\n\tswitch {\n\tcase virtualMachineID != nil:\n\t\tdata.ParentObjectType = strToPtr(\"virtualization.virtualmachine\")\n\t\tdata.ParentObjectID = virtualMachineID\n\tcase deviceID != nil:\n\t\tdata.ParentObjectType = strToPtr(\"dcim.device\")\n\t\tdata.ParentObjectID = deviceID\n\t}\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tif v, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = v.(string)\n\t}\n\n\tdata.Ipaddresses = []int64{}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := ipam.NewIpamServicesCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamServicesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxServiceUpdate(d, m)\n}\n\nfunc resourceNetboxServiceRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamServicesReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamServicesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamServicesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tservice := res.GetPayload()\n\n\td.Set(\"name\", service.Name)\n\td.Set(\"protocol\", service.Protocol.Value)\n\td.Set(\"ports\", service.Ports)\n\td.Set(\"description\", service.Description)\n\n\tparentObjectType := service.ParentObjectType\n\tswitch parentObjectType {\n\tcase \"virtualization.virtualmachine\":\n\t\td.Set(\"virtual_machine_id\", service.ParentObjectID)\n\tcase \"dcim.device\":\n\t\td.Set(\"device_id\", service.ParentObjectID)\n\t}\n\n\tif tags := service.Tags; tags != nil {\n\t\tapi.readTags(d, tags)\n\t}\n\n\tcf := getCustomFields(service.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxServiceUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableService{}\n\n\tdataName := d.Get(\"name\").(string)\n\tdata.Name = &dataName\n\n\tdataProtocol := d.Get(\"protocol\").(string)\n\tdata.Protocol = &dataProtocol\n\n\tdataPort, dataPortOk := d.GetOk(\"port\")\n\tif dataPortOk {\n\t\tdata.Ports = []int64{int64(dataPort.(int))}\n\t} else {\n\t\t// if port is not set, ports has to be set\n\t\tvar dataPorts []int64\n\t\tif v := d.Get(\"ports\").(*schema.Set); v.Len() > 0 {\n\t\t\tfor _, v := range v.List() {\n\t\t\t\tdataPorts = append(dataPorts, int64(v.(int)))\n\t\t\t}\n\t\t\tdata.Ports = dataPorts\n\t\t}\n\t}\n\n\tdata.Ipaddresses = []int64{}\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tif v, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = v.(string)\n\t}\n\n\tvirtualMachineID := getOptionalInt(d, \"virtual_machine_id\")\n\tdeviceID := getOptionalInt(d, \"device_id\")\n\n\tswitch {\n\tcase virtualMachineID != nil:\n\t\tdata.ParentObjectType = strToPtr(\"virtualization.virtualmachine\")\n\t\tdata.ParentObjectID = virtualMachineID\n\tcase deviceID != nil:\n\t\tdata.ParentObjectType = strToPtr(\"dcim.device\")\n\t\tdata.ParentObjectID = deviceID\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := ipam.NewIpamServicesUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Ipam.IpamServicesUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxServiceRead(d, m)\n}\n\nfunc resourceNetboxServiceDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamServicesDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamServicesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamServicesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_service_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc testAccNetboxServiceFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n}\n\n`, testName)\n}\n\nfunc TestAccNetboxService_basic(t *testing.T) {\n\ttestSlug := \"svc_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckServiceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxServiceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_service\" \"test\" {\n  name = \"%s\"\n  virtual_machine_id = netbox_virtual_machine.test.id\n  ports = [666]\n  protocol = \"tcp\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_service.test\", \"virtual_machine_id\", \"netbox_virtual_machine.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"ports.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"ports.0\", \"666\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"protocol\", \"tcp\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_service.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxService_customFields(t *testing.T) {\n\ttestSlug := \"svc_custom_fields\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckServiceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxServiceFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n  name          = \"custom_field\"\n  type          = \"text\"\n  content_types = [\"ipam.service\"]\n}\nresource \"netbox_service\" \"test_customfield\" {\n  name = \"%s\"\n  virtual_machine_id = netbox_virtual_machine.test.id\n  ports = [333]\n  protocol = \"tcp\"\n  custom_fields = {\"${netbox_custom_field.test.name}\" = \"testtext\"}\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test_customfield\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_service.test_customfield\", \"virtual_machine_id\", \"netbox_virtual_machine.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test_customfield\", \"ports.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test_customfield\", \"ports.0\", \"333\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test_customfield\", \"protocol\", \"tcp\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test_customfield\", \"custom_fields.custom_field\", \"testtext\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_service.test_customfield\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckServiceDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each service\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_service\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our service by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := ipam.NewIpamServicesReadParams().WithID(stateID)\n\t\t_, err := conn.Ipam.IpamServicesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"service (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*ipam.IpamServicesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc TestAccNetboxService_withDescriptionDeviceID(t *testing.T) {\n\ttestSlug := \"svc_with_desc_tags_device\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckServiceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_service\" \"test\" {\n  name = \"%s\"\n  device_id = netbox_device.test_device.id\n  ports = [666]\n  protocol = \"tcp\"\n  description = \"Test service description\"\n}\n  resource \"netbox_site\" \"test_site\" {\n  name = \"%[1]s_site\"\n  slug = \"%[1]s_site\"\n}\n\nresource \"netbox_device_role\" \"test_role\" {\n  name = \"%[1]s_role\"\n  slug = \"%[1]s_role\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_manufacturer\" \"test_manufacturer\" {\n  name = \"%[1]s_manufacturer\"\n}\n\nresource \"netbox_device_type\" \"test_type\" {\n  model = \"%[1]s_type\"\n  manufacturer_id = netbox_manufacturer.test_manufacturer.id\n}\n\nresource \"netbox_device\" \"test_device\" {\n  name = \"%[1]s_device\"\n  role_id = netbox_device_role.test_role.id\n  device_type_id = netbox_device_type.test_type.id\n  site_id = netbox_site.test_site.id\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_service.test\", \"device_id\", \"netbox_device.test_device\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"ports.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"ports.0\", \"666\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"protocol\", \"tcp\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"description\", \"Test service description\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_service.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxService_withDescriptionTagsVirtualMachine(t *testing.T) {\n\ttestSlug := \"svc_with_desc_tags_device\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckServiceDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxServiceFullDependencies(testName) + fmt.Sprintf(\n\t\t\t\t\t`\n\t\t\t\t\tresource \"netbox_tag\" \"tag1\" {\n\t\t\t\t\t\tname = \"tag1\"\n\t\t\t\t\t\tslug = \"tag1\"\n\t\t\t\t\t}\n\t\t\t\t\tresource \"netbox_tag\" \"tag2\" {\n\t\t\t\t\t\tname = \"tag2\"\n\t\t\t\t\t\tslug = \"tag2\"\n\t\t\t\t\t}\n\t\t\t\t\tresource \"netbox_service\" \"test\" {\n\t\t\t\t\t\tname = \"%s\"\n\t\t\t\t\t\tvirtual_machine_id = netbox_virtual_machine.test.id\n\t\t\t\t\t\tports = [666]\n\t\t\t\t\t\tprotocol = \"tcp\"\n\t\t\t\t\t\tdescription = \"Test service description\"\n\t\t\t\t\t\ttags = [netbox_tag.tag1.name, netbox_tag.tag2.name]\n\t\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\t\ttestName,\n\t\t\t\t),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"tags.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"tags.0\", \"tag1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"tags.1\", \"tag2\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_service.test\", \"virtual_machine_id\", \"netbox_virtual_machine.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"ports.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"ports.0\", \"666\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"protocol\", \"tcp\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_service.test\", \"description\", \"Test service description\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_service.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_service\", &resource.Sweeper{\n\t\tName:         \"netbox_service\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamServicesListParams()\n\t\t\tres, err := api.Ipam.IpamServicesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, intrface := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*intrface.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamServicesDeleteParams().WithID(intrface.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamServicesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted an interface\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_site.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxSiteStatusOptions = []string{\"planned\", \"staging\", \"active\", \"decommissioning\", \"retired\"}\n\nfunc resourceNetboxSite() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxSiteCreate,\n\t\tRead:   resourceNetboxSiteRead,\n\t\tUpdate: resourceNetboxSiteUpdate,\n\t\tDelete: resourceNetboxSiteDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#sites):\n\n> How you choose to employ sites when modeling your network may vary depending on the nature of your organization, but generally a site will equate to a building or campus. For example, a chain of banks might create a site to represent each of its branches, a site for its corporate headquarters, and two additional sites for its presence in two colocation facilities.\n>\n> Each site must be assigned a unique name and may optionally be assigned to a region and/or tenant.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tDefault:      \"active\",\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxSiteStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxSiteStatusOptions),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"facility\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 50),\n\t\t\t},\n\t\t\t\"longitude\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"latitude\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"physical_address\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t},\n\t\t\t\"shipping_address\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 200),\n\t\t\t},\n\t\t\t\"region_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"timezone\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"asn_ids\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxSiteCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableSite{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Status = d.Get(\"status\").(string)\n\n\tif description, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = description.(string)\n\t}\n\n\tif comments, ok := d.GetOk(\"comments\"); ok {\n\t\tdata.Comments = comments.(string)\n\t}\n\n\tif facility, ok := d.GetOk(\"facility\"); ok {\n\t\tdata.Facility = facility.(string)\n\t}\n\n\tlatitudeValue, ok := d.GetOk(\"latitude\")\n\tif ok {\n\t\tdata.Latitude = float64ToPtr(float64(latitudeValue.(float64)))\n\t}\n\n\tlongitudeValue, ok := d.GetOk(\"longitude\")\n\tif ok {\n\t\tdata.Longitude = float64ToPtr(float64(longitudeValue.(float64)))\n\t}\n\n\tphysicalAddressValue, ok := d.GetOk(\"physical_address\")\n\tif ok {\n\t\tdata.PhysicalAddress = physicalAddressValue.(string)\n\t}\n\n\tshippingAddressValue, ok := d.GetOk(\"shipping_address\")\n\tif ok {\n\t\tdata.ShippingAddress = shippingAddressValue.(string)\n\t}\n\n\tregionIDValue, ok := d.GetOk(\"region_id\")\n\tif ok {\n\t\tdata.Region = int64ToPtr(int64(regionIDValue.(int)))\n\t}\n\n\tgroupIDValue, ok := d.GetOk(\"group_id\")\n\tif ok {\n\t\tdata.Group = int64ToPtr(int64(groupIDValue.(int)))\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantIDValue.(int)))\n\t}\n\n\tif timezone, ok := d.GetOk(\"timezone\"); ok {\n\t\tdata.TimeZone = strToPtr(timezone.(string))\n\t}\n\n\tdata.Asns = []int64{}\n\tif asnsValue, ok := d.GetOk(\"asn_ids\"); ok {\n\t\tdata.Asns = toInt64List(asnsValue)\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := dcim.NewDcimSitesCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimSitesCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxSiteRead(d, m)\n}\n\nfunc resourceNetboxSiteRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimSitesReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimSitesRead(params, nil)\n\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimSitesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tsite := res.GetPayload()\n\n\td.Set(\"name\", site.Name)\n\td.Set(\"slug\", site.Slug)\n\td.Set(\"status\", site.Status.Value)\n\td.Set(\"description\", site.Description)\n\td.Set(\"comments\", site.Comments)\n\td.Set(\"facility\", site.Facility)\n\td.Set(\"longitude\", site.Longitude)\n\td.Set(\"latitude\", site.Latitude)\n\td.Set(\"physical_address\", site.PhysicalAddress)\n\td.Set(\"shipping_address\", site.ShippingAddress)\n\td.Set(\"timezone\", site.TimeZone)\n\td.Set(\"asn_ids\", getIDsFromNestedASNList(site.Asns))\n\n\tif res.GetPayload().Region != nil {\n\t\td.Set(\"region_id\", res.GetPayload().Region.ID)\n\t} else {\n\t\td.Set(\"region_id\", nil)\n\t}\n\n\tif res.GetPayload().Group != nil {\n\t\td.Set(\"group_id\", res.GetPayload().Group.ID)\n\t} else {\n\t\td.Set(\"group_id\", nil)\n\t}\n\n\tif res.GetPayload().Tenant != nil {\n\t\td.Set(\"tenant_id\", res.GetPayload().Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, res.GetPayload().Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxSiteUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableSite{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tdata.Slug = strToPtr(getSlug(name))\n\t} else {\n\t\tdata.Slug = strToPtr(slugValue.(string))\n\t}\n\n\tdata.Status = d.Get(\"status\").(string)\n\n\tif description, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = description.(string)\n\t} else if d.HasChange(\"description\") {\n\t\t// If GetOK returned unset description and its value changed, set it as a space string to delete it ...\n\t\tdata.Description = \" \"\n\t}\n\n\tif comments, ok := d.GetOk(\"comments\"); ok {\n\t\tdata.Comments = comments.(string)\n\t} else if d.HasChange(\"comments\") {\n\t\t// If GetOK returned unset description and its value changed, set it as a space string to delete it ...\n\t\tdata.Comments = \" \"\n\t}\n\n\tif facility, ok := d.GetOk(\"facility\"); ok {\n\t\tdata.Facility = facility.(string)\n\t}\n\n\tlatitudeValue, ok := d.GetOk(\"latitude\")\n\tif ok {\n\t\tdata.Latitude = float64ToPtr(float64(latitudeValue.(float64)))\n\t}\n\n\tlongitudeValue, ok := d.GetOk(\"longitude\")\n\tif ok {\n\t\tdata.Longitude = float64ToPtr(float64(longitudeValue.(float64)))\n\t}\n\n\tphysicalAddressValue, ok := d.GetOk(\"physical_address\")\n\tif ok {\n\t\tdata.PhysicalAddress = physicalAddressValue.(string)\n\t} else if d.HasChange(\"physical_address\") {\n\t\t// If GetOK returned unset description and its value changed, set it as a space string to delete it ...\n\t\tdata.PhysicalAddress = \" \"\n\t}\n\n\tshippingAddressValue, ok := d.GetOk(\"shipping_address\")\n\tif ok {\n\t\tdata.ShippingAddress = shippingAddressValue.(string)\n\t} else if d.HasChange(\"shipping_address\") {\n\t\t// If GetOK returned unset description and its value changed, set it as a space string to delete it ...\n\t\tdata.ShippingAddress = \" \"\n\t}\n\n\tregionIDValue, ok := d.GetOk(\"region_id\")\n\tif ok {\n\t\tdata.Region = int64ToPtr(int64(regionIDValue.(int)))\n\t}\n\n\tgroupIDValue, ok := d.GetOk(\"group_id\")\n\tif ok {\n\t\tdata.Group = int64ToPtr(int64(groupIDValue.(int)))\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantIDValue.(int)))\n\t}\n\n\tif timezone, ok := d.GetOk(\"timezone\"); ok {\n\t\tdata.TimeZone = strToPtr(timezone.(string))\n\t}\n\n\tdata.Asns = []int64{}\n\tif asnsValue, ok := d.GetOk(\"asn_ids\"); ok {\n\t\tdata.Asns = toInt64List(asnsValue)\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := dcim.NewDcimSitesPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimSitesPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxSiteRead(d, m)\n}\n\nfunc resourceNetboxSiteDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimSitesDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimSitesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimSitesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc getIDsFromNestedASNList(nestedASNs []*models.NestedASN) []int64 {\n\tvar asns []int64\n\tfor _, asn := range nestedASNs {\n\t\tasns = append(asns, asn.ID)\n\t}\n\treturn asns\n}\n"
  },
  {
    "path": "netbox/resource_netbox_site_group.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxSiteGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxSiteGroupCreate,\n\t\tRead:   resourceNetboxSiteGroupRead,\n\t\tUpdate: resourceNetboxSiteGroupUpdate,\n\t\tDelete: resourceNetboxSiteGroupDelete,\n\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/facilities/#site-groups):\n\n> Like regions, site groups can be arranged in a recursive hierarchy for grouping sites. However, whereas regions are intended for geographic organization, site groups may be used for functional grouping. For example, you might classify sites as corporate, branch, or customer sites in addition to where they are physically located.\n>\n> The use of both regions and site groups affords to independent but complementary dimensions across which sites can be organized.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxSiteGroupCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparentID := int64(d.Get(\"parent_id\").(int))\n\tdescription := d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata := &models.WritableSiteGroup{}\n\tdata.Name = &name\n\tdata.Slug = &slug\n\tdata.Description = description\n\tdata.Tags = []*models.NestedTag{}\n\n\tif parentID != 0 {\n\t\tdata.Parent = &parentID\n\t}\n\n\tparams := dcim.NewDcimSiteGroupsCreateParams().WithData(data)\n\n\tres, err := api.Dcim.DcimSiteGroupsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxSiteGroupRead(d, m)\n}\n\nfunc resourceNetboxSiteGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := dcim.NewDcimSiteGroupsReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimSiteGroupsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimSiteGroupsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tsiteGroup := res.GetPayload()\n\td.Set(\"name\", siteGroup.Name)\n\td.Set(\"slug\", siteGroup.Slug)\n\td.Set(\"description\", siteGroup.Description)\n\tif siteGroup.Parent != nil {\n\t\td.Set(\"parent_id\", siteGroup.Parent.ID)\n\t}\n\treturn nil\n}\n\nfunc resourceNetboxSiteGroupUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableSiteGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tparentID := int64(d.Get(\"parent_id\").(int))\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.Description = description\n\tdata.Tags = []*models.NestedTag{}\n\n\tif parentID != 0 {\n\t\tdata.Parent = &parentID\n\t}\n\tparams := dcim.NewDcimSiteGroupsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Dcim.DcimSiteGroupsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxSiteGroupRead(d, m)\n}\n\nfunc resourceNetboxSiteGroupDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimSiteGroupsDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimSiteGroupsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimSiteGroupsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_site_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxSiteGroup_basic(t *testing.T) {\n\ttestSlug := \"s_grp_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site_group\" \"parent\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  description = \"foo bar.\"\n}\n\nresource \"netbox_site_group\" \"child\" {\n  name = \"%[1]s-child\"\n  slug = \"%[2]s-c\"\n\n  parent_id = netbox_site_group.parent.id\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site_group.parent\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site_group.parent\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site_group.parent\", \"description\", \"foo bar.\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site_group.child\", \"name\", fmt.Sprintf(\"%s-child\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site_group.child\", \"slug\", fmt.Sprintf(\"%s-c\", randomSlug)),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_site_group.child\", \"parent_id\", \"netbox_site_group.parent\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_site_group.parent\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxSiteGroup_defaultSlug(t *testing.T) {\n\ttestSlug := \"sitegrp_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site_group\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site_group.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_site_group\", &resource.Sweeper{\n\t\tName:         \"netbox_site_group\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimSiteGroupsListParams()\n\t\t\tres, err := api.Dcim.DcimSiteGroupsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, siteGroup := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*siteGroup.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimSiteGroupsDeleteParams().WithID(siteGroup.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimSiteGroupsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a site group\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_site_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxSite_basic(t *testing.T) {\n\ttestSlug := \"site_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site_group\" \"test\" {\n  name = \"%[1]s\"\n}\nresource \"netbox_rir\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_asn\" \"test\" {\n  asn = 1338\n  rir_id = netbox_rir.test.id\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[2]s\"\n  status = \"planned\"\n  description = \"%[1]s\"\n  comments = \"%[1]s\"\n  facility = \"%[1]s\"\n  physical_address = \"%[1]s\"\n  shipping_address = \"%[1]s\"\n  asn_ids = [netbox_asn.test.id]\n  group_id = netbox_site_group.test.id\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"status\", \"planned\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"description\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"comments\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"facility\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"physical_address\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"shipping_address\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"asn_ids.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_site.test\", \"asn_ids.0\", \"netbox_asn.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_site.test\", \"group_id\", \"netbox_site_group.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_site.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxSite_customFields(t *testing.T) {\n\ttestSlug := \"site_detail\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestField := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n\tname          = \"%[1]s\"\n\ttype          = \"text\"\n\tcontent_types = [\"dcim.site\"]\n}\nresource \"netbox_site\" \"test\" {\n  name          = \"%[2]s\"\n  status        = \"decommissioning\"\n  latitude      = \"12.123456\"\n  longitude     = \"-13.123456\"\n  timezone      = \"Africa/Johannesburg\"\n  custom_fields = {\"${netbox_custom_field.test.name}\" = \"81\"}\n}`, testField, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"status\", \"decommissioning\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"custom_fields.\"+testField, \"81\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"timezone\", \"Africa/Johannesburg\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"latitude\", \"12.123456\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"longitude\", \"-13.123456\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxSite_fieldUpdate(t *testing.T) {\n\ttestSlug := \"site_field_update\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestField := strings.ReplaceAll(testAccGetTestName(testSlug), \"-\", \"_\")\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n\tname        = \"%[2]s\"\n\tdescription = \"Test site description\"\n\tcomments = \"Test comment\"\n\tphysical_address = \"Physical address\"\n\tshipping_address = \"Shipping address\"\n\tlatitude      = \"12.123456\"\n  \tlongitude     = \"-13.123456\"\n\n}`, testField, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"description\", \"Test site description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"comments\", \"Test comment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"physical_address\", \"Physical address\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"shipping_address\", \"Shipping address\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"latitude\", \"12.123456\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"longitude\", \"-13.123456\"),\n\t\t\t\t)},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n\tname = \"%[2]s\"\n}`, testField, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"physical_address\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"shipping_address\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"latitude\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_site.test\", \"longitude\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_site\", &resource.Sweeper{\n\t\tName:         \"netbox_site\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := dcim.NewDcimSitesListParams()\n\t\t\tres, err := api.Dcim.DcimSitesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, site := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*site.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := dcim.NewDcimSitesDeleteParams().WithID(site.ID)\n\t\t\t\t\t_, err := api.Dcim.DcimSitesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a site\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_tag.go",
    "content": "package netbox\n\nimport (\n\t\"regexp\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxTag() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxTagCreate,\n\t\tRead:   resourceNetboxTagRead,\n\t\tUpdate: resourceNetboxTagUpdate,\n\t\tDelete: resourceNetboxTagDelete,\n\n\t\tDescription: `:meta:subcategory:Extras:From the [official documentation](https://docs.netbox.dev/en/stable/models/extras/tag/):\n> Tags are user-defined labels which can be applied to a variety of objects within NetBox. They can be used to establish dimensions of organization beyond the relationships built into NetBox. For example, you might create a tag to identify a particular ownership or condition across several types of objects.\n>\n> Each tag has a label, color, and a URL-friendly slug. For example, the slug for a tag named \"Dunder Mifflin, Inc.\" would be dunder-mifflin-inc. The slug is generated automatically and makes tags easier to work with as URL parameters. Each tag can also be assigned a description indicating its purpose.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"color_hex\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tDefault:      \"9e9e9e\",\n\t\t\t\tValidateFunc: validation.StringMatch(regexp.MustCompile(\"^[0-9a-f]{6}$\"), \"Must be hex color string\"),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxTagCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tcolor := d.Get(\"color_hex\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tparams := extras.NewExtrasTagsCreateParams().WithData(\n\t\t&models.Tag{\n\t\t\tName:        &name,\n\t\t\tSlug:        &slug,\n\t\t\tColor:       color,\n\t\t\tDescription: description,\n\t\t},\n\t)\n\n\tres, err := api.Extras.ExtrasTagsCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxTagRead(d, m)\n}\n\nfunc resourceNetboxTagRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasTagsReadParams().WithID(id)\n\n\tres, err := api.Extras.ExtrasTagsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasTagsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"color_hex\", res.GetPayload().Color)\n\td.Set(\"description\", res.GetPayload().Description)\n\treturn nil\n}\n\nfunc resourceNetboxTagUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.Tag{}\n\n\tname := d.Get(\"name\").(string)\n\tcolor := d.Get(\"color_hex\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.Color = color\n\tdata.Description = description\n\n\tparams := extras.NewExtrasTagsUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Extras.ExtrasTagsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxTagRead(d, m)\n}\n\nfunc resourceNetboxTagDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasTagsDeleteParams().WithID(id)\n\n\t_, err := api.Extras.ExtrasTagsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasTagsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_tag_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxTag_basic(t *testing.T) {\n\ttestSlug := \"tag_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n  color_hex = \"112233\"\n  description = \"This is a test\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tag.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tag.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tag.test\", \"color_hex\", \"112233\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tag.test\", \"description\", \"This is a test\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_tag.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxTag_defaultSlug(t *testing.T) {\n\ttestSlug := \"tag_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tag.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tag.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_tag\", &resource.Sweeper{\n\t\tName:         \"netbox_tag\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := extras.NewExtrasTagsListParams()\n\t\t\tres, err := api.Extras.ExtrasTagsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tag := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*tag.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := extras.NewExtrasTagsDeleteParams().WithID(tag.ID)\n\t\t\t\t\t_, err := api.Extras.ExtrasTagsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a tag\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_tenant.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxTenant() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxTenantCreate,\n\t\tRead:   resourceNetboxTenantRead,\n\t\tUpdate: resourceNetboxTenantUpdate,\n\t\tDelete: resourceNetboxTenantDelete,\n\n\t\tDescription: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/tenancy/#tenants):\n\n> A tenant represents a discrete grouping of resources used for administrative purposes. Typically, tenants are used to represent individual customers or internal departments within an organization.\n>\n> Tenant assignment is used to signify the ownership of an object in NetBox. As such, each object may only be owned by a single tenant. For example, if you have a firewall dedicated to a particular customer, you would assign it to the tenant which represents that customer. However, if the firewall serves multiple customers, it doesn't belong to any particular customer, so tenant assignment would not be appropriate.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxTenantCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tgroupID := int64(d.Get(\"group_id\").(int))\n\tdescription := d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tdata := &models.WritableTenant{}\n\n\tdata.Name = &name\n\tdata.Slug = &slug\n\tdata.Description = description\n\tdata.Tags = tags\n\n\tif groupID != 0 {\n\t\tdata.Group = &groupID\n\t}\n\n\tparams := tenancy.NewTenancyTenantsCreateParams().WithData(data)\n\n\tres, err := api.Tenancy.TenancyTenantsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxTenantRead(d, m)\n}\n\nfunc resourceNetboxTenantRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyTenantsReadParams().WithID(id)\n\n\tres, err := api.Tenancy.TenancyTenantsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyTenantsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"description\", res.GetPayload().Description)\n\tif res.GetPayload().Group != nil {\n\t\td.Set(\"group_id\", res.GetPayload().Group.ID)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxTenantUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableTenant{}\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tgroupID := int64(d.Get(\"group_id\").(int))\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.Description = description\n\tdata.Tags = tags\n\tif groupID != 0 {\n\t\tdata.Group = &groupID\n\t}\n\n\tparams := tenancy.NewTenancyTenantsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Tenancy.TenancyTenantsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxTenantRead(d, m)\n}\n\nfunc resourceNetboxTenantDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyTenantsDeleteParams().WithID(id)\n\n\t_, err := api.Tenancy.TenancyTenantsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyTenantsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_tenant_group.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxTenantGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxTenantGroupCreate,\n\t\tRead:   resourceNetboxTenantGroupRead,\n\t\tUpdate: resourceNetboxTenantGroupUpdate,\n\t\tDelete: resourceNetboxTenantGroupDelete,\n\n\t\tDescription: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/tenancy/#tenant-groups):\n\n> Tenants can be organized by custom groups. For instance, you might create one group called \"Customers\" and one called \"Departments.\" The assignment of a tenant to a group is optional.\n>\n> Tenant groups may be nested recursively to achieve a multi-level hierarchy. For example, you might have a group called \"Customers\" containing subgroups of individual tenants grouped by product or account team.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxTenantGroupCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tparentID := int64(d.Get(\"parent_id\").(int))\n\tdescription := d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata := &models.WritableTenantGroup{}\n\tdata.Name = &name\n\tdata.Slug = &slug\n\tdata.Description = description\n\tdata.Tags = []*models.NestedTag{}\n\n\tif parentID != 0 {\n\t\tdata.Parent = &parentID\n\t}\n\n\tparams := tenancy.NewTenancyTenantGroupsCreateParams().WithData(data)\n\n\tres, err := api.Tenancy.TenancyTenantGroupsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxTenantGroupRead(d, m)\n}\n\nfunc resourceNetboxTenantGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := tenancy.NewTenancyTenantGroupsReadParams().WithID(id)\n\n\tres, err := api.Tenancy.TenancyTenantGroupsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyTenantGroupsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"description\", res.GetPayload().Description)\n\tif res.GetPayload().Parent != nil {\n\t\td.Set(\"parent\", res.GetPayload().Parent.ID)\n\t}\n\treturn nil\n}\n\nfunc resourceNetboxTenantGroupUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableTenantGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tparentID := int64(d.Get(\"parent_id\").(int))\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata.Slug = &slug\n\tdata.Name = &name\n\tdata.Description = description\n\tdata.Tags = []*models.NestedTag{}\n\n\tif parentID != 0 {\n\t\tdata.Parent = &parentID\n\t}\n\tparams := tenancy.NewTenancyTenantGroupsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Tenancy.TenancyTenantGroupsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxTenantGroupRead(d, m)\n}\n\nfunc resourceNetboxTenantGroupDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := tenancy.NewTenancyTenantGroupsDeleteParams().WithID(id)\n\n\t_, err := api.Tenancy.TenancyTenantGroupsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*tenancy.TenancyTenantGroupsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_tenant_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxTenantGroup_basic(t *testing.T) {\n\ttestSlug := \"t_grp_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant_group\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant_group.test\", \"slug\", randomSlug),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_tenant_group.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxTenantGroup_defaultSlug(t *testing.T) {\n\ttestSlug := \"tenant_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant_group\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant_group.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_tenant_group\", &resource.Sweeper{\n\t\tName:         \"netbox_tenant_group\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := tenancy.NewTenancyTenantGroupsListParams()\n\t\t\tres, err := api.Tenancy.TenancyTenantGroupsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tenant := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*tenant.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := tenancy.NewTenancyTenantGroupsDeleteParams().WithID(tenant.ID)\n\t\t\t\t\t_, err := api.Tenancy.TenancyTenantGroupsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a tenant group\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_tenant_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/tenancy\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxTenantTagDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_tag\" \"test_b\" {\n  name = \"%[1]sb\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxTenant_basic(t *testing.T) {\n\ttestSlug := \"tenant_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestDescription := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%s\"\n  slug = \"%s\"\n  description = \"%s\"\n}`, testName, randomSlug, testDescription),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test\", \"description\", testDescription),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_tenant.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxTenant_defaultSlug(t *testing.T) {\n\ttestSlug := \"tenant_defSlug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tenant\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxTenant_tags(t *testing.T) {\n\ttestSlug := \"tenant_tags\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxTenantTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_tenant\" \"test_tags\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test_tags\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test_tags\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test_tags\", \"tags.0\", testName+\"a\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxTenantTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_tenant\" \"test_tags\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name, netbox_tag.test_b.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test_tags\", \"tags.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test_tags\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test_tags\", \"tags.1\", testName+\"b\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxTenantTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_tenant\" \"test_tags\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_tenant.test_tags\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_tenant\", &resource.Sweeper{\n\t\tName:         \"netbox_tenant\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := tenancy.NewTenancyTenantsListParams()\n\t\t\tres, err := api.Tenancy.TenancyTenantsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tenant := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*tenant.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := tenancy.NewTenancyTenantsDeleteParams().WithID(tenant.ID)\n\t\t\t\t\t_, err := api.Tenancy.TenancyTenantsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a tenant\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_token.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/users\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/go-openapi/strfmt\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxToken() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxTokenCreate,\n\t\tReadContext:   resourceNetboxTokenRead,\n\t\tUpdateContext: resourceNetboxTokenUpdate,\n\t\tDeleteContext: resourceNetboxTokenDelete,\n\n\t\tDescription: `:meta:subcategory:Authentication:From the [official documentation](https://docs.netbox.dev/en/stable/rest-api/authentication/#tokens):\n\n> A token is a unique identifier mapped to a NetBox user account. Each user may have one or more tokens which he or she can use for authentication when making REST API requests. To create a token, navigate to the API tokens page under your user profile.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"user_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"key\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tSensitive:    true,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(40, 256),\n\t\t\t},\n\t\t\t\"allowed_ips\": {\n\t\t\t\tType:     schema.TypeList,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType:         schema.TypeString,\n\t\t\t\t\tValidateFunc: validation.IsCIDR,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"write_enabled\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"last_used\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"expires\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.IsRFC3339Time,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxTokenCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tdata := models.WritableToken{}\n\n\tuserid := int64(d.Get(\"user_id\").(int))\n\n\tkey := d.Get(\"key\").(string)\n\tallowedIps := d.Get(\"allowed_ips\").([]interface{})\n\n\tdata.User = &userid\n\tdata.Key = key\n\n\tdata.AllowedIps = make([]models.IPNetwork, len(allowedIps))\n\tfor i, v := range allowedIps {\n\t\tdata.AllowedIps[i] = v\n\t}\n\n\tdata.WriteEnabled = d.Get(\"write_enabled\").(bool)\n\tdata.Description = d.Get(\"description\").(string)\n\n\tif expiresRaw, ok := d.GetOk(\"expires\"); ok {\n\t\texpires, err := strfmt.ParseDateTime(expiresRaw.(string))\n\t\tif err != nil {\n\t\t\treturn diag.FromErr(err)\n\t\t}\n\t\tdata.Expires = &expires\n\t}\n\n\tparams := users.NewUsersTokensCreateParams().WithData(&data)\n\tres, err := api.Users.UsersTokensCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxTokenUpdate(ctx, d, m)\n}\n\nfunc resourceNetboxTokenRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := users.NewUsersTokensReadParams().WithID(id)\n\n\tres, err := api.Users.UsersTokensRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*users.UsersTokensReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\ttoken := res.GetPayload()\n\n\tif token.User != nil {\n\t\td.Set(\"user_id\", token.User.ID)\n\t}\n\n\t// Since NetBox 4.3.0, ALLOW_TOKEN_RETRIEVAL is disabled by default\n\t// This means we will usually not get a Key value from the API\n\tif token.Key != \"\" {\n\t\td.Set(\"key\", token.Key)\n\t}\n\td.Set(\"last_used\", token.LastUsed)\n\tif token.Expires != nil {\n\t\td.Set(\"expires\", token.Expires.String())\n\t}\n\td.Set(\"allowed_ips\", token.AllowedIps)\n\td.Set(\"write_enabled\", token.WriteEnabled)\n\td.Set(\"description\", token.Description)\n\n\treturn nil\n}\n\nfunc resourceNetboxTokenUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableToken{}\n\n\tuserid := int64(d.Get(\"user_id\").(int))\n\tkey := d.Get(\"key\").(string)\n\tallowedIps := d.Get(\"allowed_ips\").([]interface{})\n\n\tdata.User = &userid\n\tdata.Key = key\n\n\tdata.AllowedIps = make([]models.IPNetwork, len(allowedIps))\n\tfor i, v := range allowedIps {\n\t\tdata.AllowedIps[i] = v\n\t}\n\n\tdata.WriteEnabled = d.Get(\"write_enabled\").(bool)\n\tdata.Description = d.Get(\"description\").(string)\n\n\tif expiresRaw, ok := d.GetOk(\"expires\"); ok {\n\t\texpires, err := strfmt.ParseDateTime(expiresRaw.(string))\n\t\tif err != nil {\n\t\t\treturn diag.FromErr(err)\n\t\t}\n\t\tdata.Expires = &expires\n\t}\n\n\tparams := users.NewUsersTokensUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Users.UsersTokensUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\treturn resourceNetboxTokenRead(ctx, d, m)\n}\n\nfunc resourceNetboxTokenDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := users.NewUsersTokensDeleteParams().WithID(id)\n\t_, err := api.Users.UsersTokensDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*users.UsersTokensDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_token_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/users\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxToken_basic(t *testing.T) {\n\ttestSlug := \"users\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestToken := testAccGetTestToken()\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_user\" \"test\" {\n  username = \"%s\"\n  password = \"Abcdefghijkl1\"\n}\n\nresource \"netbox_token\" \"test_basic\" {\n  user_id       = netbox_user.test.id\n  key           = \"%s\"\n  allowed_ips   = [\"2.4.8.16/32\"]\n  write_enabled = false\n  description   = \"Netbox Test Basic Token\"\n  expires       = \"2036-01-02T15:04:05.000Z\"\n}`, testName, testToken),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_basic\", \"key\", testToken),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_basic\", \"allowed_ips.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_basic\", \"allowed_ips.0\", \"2.4.8.16/32\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_basic\", \"write_enabled\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_basic\", \"description\", \"Netbox Test Basic Token\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_basic\", \"expires\", \"2036-01-02T15:04:05.000Z\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_token.test_basic\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"key\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxToken_withoutExpires(t *testing.T) {\n\ttestSlug := \"users\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestToken := testAccGetTestToken()\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_user\" \"test\" {\n  username = \"%s\"\n  password = \"Abcdefghijkl1\"\n}\n\nresource \"netbox_token\" \"test_without_expires\" {\n  user_id       = netbox_user.test.id\n  key           = \"%s\"\n  allowed_ips   = [\"2.4.8.16/32\"]\n  write_enabled = false\n  description   = \"Netbox Token Without Expires\"\n}`, testName, testToken),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_without_expires\", \"key\", testToken),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_without_expires\", \"allowed_ips.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_without_expires\", \"allowed_ips.0\", \"2.4.8.16/32\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_without_expires\", \"write_enabled\", \"false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_token.test_without_expires\", \"description\", \"Netbox Token Without Expires\"),\n\t\t\t\t\tresource.TestCheckNoResourceAttr(\"netbox_token.test_without_expires\", \"expires\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_token.test_without_expires\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"key\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_token\", &resource.Sweeper{\n\t\tName:         \"netbox_token\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := users.NewUsersUsersListParams()\n\t\t\tres, err := api.Users.UsersUsersList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, user := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*user.Username, testPrefix) {\n\t\t\t\t\tdeleteParams := users.NewUsersUsersDeleteParams().WithID(user.ID)\n\t\t\t\t\t_, err := api.Users.UsersUsersDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a token\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_user.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/users\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/go-openapi/strfmt\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxUser() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxUserCreate,\n\t\tRead:   resourceNetboxUserRead,\n\t\tUpdate: resourceNetboxUserUpdate,\n\t\tDelete: resourceNetboxUserDelete,\n\n\t\tDescription: `:meta:subcategory:Authentication:This resource is used to manage users.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"username\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"password\": {\n\t\t\t\tType:      schema.TypeString,\n\t\t\t\tRequired:  true,\n\t\t\t\tSensitive: true,\n\t\t\t},\n\t\t\t\"email\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  \"\",\n\t\t\t},\n\t\t\t\"first_name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  \"\",\n\t\t\t},\n\t\t\t\"last_name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  \"\",\n\t\t\t},\n\t\t\t\"active\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  true,\n\t\t\t},\n\t\t\t\"staff\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  false,\n\t\t\t},\n\t\t\t\"group_ids\": {\n\t\t\t\tType:     schema.TypeSet,\n\t\t\t\tOptional: true,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\nfunc resourceNetboxUserCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableUser{}\n\n\tusername := d.Get(\"username\").(string)\n\tpassword := d.Get(\"password\").(string)\n\temail := d.Get(\"email\").(string)\n\tfirstName := d.Get(\"first_name\").(string)\n\tlastName := d.Get(\"last_name\").(string)\n\tactive := d.Get(\"active\").(bool)\n\tstaff := d.Get(\"staff\").(bool)\n\tgroupIDs := toInt64List(d.Get(\"group_ids\"))\n\n\tdata.Username = &username\n\tdata.Password = &password\n\tdata.Email = strfmt.Email(email)\n\tdata.FirstName = firstName\n\tdata.LastName = lastName\n\tdata.IsActive = active\n\tdata.IsStaff = staff\n\tdata.Groups = groupIDs\n\tdata.DateJoined = strfmt.DateTime(time.Now())\n\n\tparams := users.NewUsersUsersCreateParams().WithData(&data)\n\tres, err := api.Users.UsersUsersCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxUserRead(d, m)\n}\n\nfunc resourceNetboxUserRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := users.NewUsersUsersReadParams().WithID(id)\n\n\tres, err := api.Users.UsersUsersRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*users.UsersUsersReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tif res.GetPayload().Username != nil {\n\t\td.Set(\"username\", res.GetPayload().Username)\n\t}\n\n\td.Set(\"email\", res.GetPayload().Email)\n\td.Set(\"first_name\", res.GetPayload().FirstName)\n\td.Set(\"last_name\", res.GetPayload().LastName)\n\n\td.Set(\"staff\", res.GetPayload().IsStaff)\n\td.Set(\"active\", res.GetPayload().IsActive)\n\td.Set(\"group_ids\", getIDsFromNestedGroup(res.GetPayload().Groups))\n\n\t// Passwords cannot be set and not read\n\n\treturn nil\n}\n\nfunc resourceNetboxUserUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableUser{}\n\n\tusername := d.Get(\"username\").(string)\n\tpassword := d.Get(\"password\").(string)\n\temail := d.Get(\"email\").(string)\n\tfirstName := d.Get(\"first_name\").(string)\n\tlastName := d.Get(\"last_name\").(string)\n\tactive := d.Get(\"active\").(bool)\n\tstaff := d.Get(\"staff\").(bool)\n\tgroupIDs := toInt64List(d.Get(\"group_ids\"))\n\n\tdata.Username = &username\n\tdata.Password = &password\n\tdata.Email = strfmt.Email(email)\n\tdata.FirstName = firstName\n\tdata.LastName = lastName\n\tdata.IsActive = active\n\tdata.IsStaff = staff\n\tdata.Groups = groupIDs\n\tdata.DateJoined = strfmt.DateTime(time.Now())\n\n\tparams := users.NewUsersUsersUpdateParams().WithID(id).WithData(&data)\n\t_, err := api.Users.UsersUsersUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxUserRead(d, m)\n}\n\nfunc resourceNetboxUserDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := users.NewUsersUsersDeleteParams().WithID(id)\n\t_, err := api.Users.UsersUsersDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*users.UsersUsersDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\td.SetId(\"\")\n\treturn nil\n}\n\nfunc getIDsFromNestedGroup(nestedGroups []*models.NestedGroup) []int64 {\n\tvar groupIDs []int64\n\tfor _, group := range nestedGroups {\n\t\tgroupIDs = append(groupIDs, group.ID)\n\t}\n\treturn groupIDs\n}\n"
  },
  {
    "path": "netbox/resource_netbox_user_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/users\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxUser_basic(t *testing.T) {\n\ttestSlug := \"users\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_user\" \"test_basic\" {\n  username = \"%s\"\n  password = \"Abcdefghijkl1\"\n  active = true\n  staff = true\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"username\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"active\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"staff\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_user\" \"test_basic\" {\n  username = \"%s\"\n  password = \"Abcdefghijkl1\"\n\temail = \"foo@bar.com\"\n\tfirst_name = \"Hannah\"\n\tlast_name = \"Acker\"\n  active = true\n  staff = true\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"username\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"email\", \"foo@bar.com\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"first_name\", \"Hannah\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"last_name\", \"Acker\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"active\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_basic\", \"staff\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_user.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: false,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxUser_group(t *testing.T) {\n\ttestSlug := \"users\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_group\" \"test_group\" {\n\t  name = \"%[1]s-group\"\n}\n\nresource \"netbox_user\" \"test_group\" {\n\t  username = \"%[1]s\"\n\t  password = \"Abcdefghijkl1\"\n\t  active = true\n\t  staff = true\n\t  group_ids = [netbox_group.test_group.id]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_group\", \"username\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_group\", \"active\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_group\", \"staff\", \"true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_user.test_group\", \"group_ids.#\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_user.test_group\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: false,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_user\", &resource.Sweeper{\n\t\tName:         \"netbox_user\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := users.NewUsersUsersListParams()\n\t\t\tres, err := api.Users.UsersUsersList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, user := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*user.Username, testPrefix) {\n\t\t\t\t\tdeleteParams := users.NewUsersUsersDeleteParams().WithID(user.ID)\n\t\t\t\t\t_, err := api.Users.UsersUsersDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a user\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_chassis.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxVirtualChassis() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxVirtualChassisCreate,\n\t\tReadContext:   resourceNetboxVirtualChassisRead,\n\t\tUpdateContext: resourceNetboxVirtualChassisUpdate,\n\t\tDeleteContext: resourceNetboxVirtualChassisDelete,\n\t\tDescription: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/devices-cabling/#virtual-chassis):\n\n\t\t> Sometimes it is necessary to model a set of physical devices as sharing a single management plane. Perhaps the most common example of such a scenario is stackable switches. These can be modeled as virtual chassis in NetBox, with one device acting as the chassis master and the rest as members. All components of member devices will appear on the master.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"domain\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVirtualChassisCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tdata := models.WritableVirtualChassis{\n\t\tName: &name,\n\t}\n\n\tdomainValue, ok := d.GetOk(\"domain\")\n\tif ok {\n\t\tdomain := domainValue.(string)\n\t\tdata.Domain = domain\n\t}\n\n\tdescriptionValue, ok := d.GetOk(\"description\")\n\tif ok {\n\t\tdescription := descriptionValue.(string)\n\t\tdata.Description = description\n\t}\n\n\tcommentsValue, ok := d.GetOk(\"comments\")\n\tif ok {\n\t\tcomments := commentsValue.(string)\n\t\tdata.Comments = comments\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tparams := dcim.NewDcimVirtualChassisCreateParams().WithData(&data)\n\n\tres, err := api.Dcim.DcimVirtualChassisCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVirtualChassisRead(ctx, d, m)\n}\n\nfunc resourceNetboxVirtualChassisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := dcim.NewDcimVirtualChassisReadParams().WithID(id)\n\n\tres, err := api.Dcim.DcimVirtualChassisRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimVirtualChassisReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\tvirtualChassis := res.GetPayload()\n\n\td.Set(\"name\", virtualChassis.Name)\n\td.Set(\"domain\", virtualChassis.Domain)\n\td.Set(\"description\", virtualChassis.Description)\n\td.Set(\"comments\", virtualChassis.Comments)\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\tapi.readTags(d, virtualChassis.Tags)\n\treturn nil\n}\n\nfunc resourceNetboxVirtualChassisUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableVirtualChassis{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tdomainValue, ok := d.GetOk(\"domain\")\n\tif ok {\n\t\tdomain := domainValue.(string)\n\t\tdata.Domain = domain\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tif d.HasChanges(\"comments\") {\n\t\t// check if comment is set\n\t\tif commentsValue, ok := d.GetOk(\"comments\"); ok {\n\t\t\tdata.Comments = commentsValue.(string)\n\t\t} else {\n\t\t\tdata.Comments = \" \"\n\t\t}\n\t}\n\tif d.HasChanges(\"description\") {\n\t\t// check if description is set\n\t\tif descriptionValue, ok := d.GetOk(\"description\"); ok {\n\t\t\tdata.Description = descriptionValue.(string)\n\t\t} else {\n\t\t\tdata.Description = \" \"\n\t\t}\n\t}\n\n\tparams := dcim.NewDcimVirtualChassisUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Dcim.DcimVirtualChassisUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn resourceNetboxVirtualChassisRead(ctx, d, m)\n}\n\nfunc resourceNetboxVirtualChassisDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := dcim.NewDcimVirtualChassisDeleteParams().WithID(id)\n\n\t_, err := api.Dcim.DcimVirtualChassisDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*dcim.DcimVirtualChassisDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn nil\n}\n\nfunc virtualChassisUpdateMaster(api *providerState, id int64, master *int64) error {\n\t// Need to read the virtual chassis because we cannot do a partial update\n\t// because setting `master` to nil would omit it entirely, so we need to\n\t// do a PUT request instead of PATCH\n\tvcRes, err := api.Dcim.DcimVirtualChassisRead(dcim.NewDcimVirtualChassisReadParams().WithID(id), nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvcData := vcRes.GetPayload()\n\tvcData.Master = nil\n\tnewTags := make([]*models.NestedTag, 0)\n\tfor _, Tag := range vcData.Tags {\n\t\tTag.Display = \"\"\n\t\tTag.ID = 0\n\t\tTag.URL = \"\"\n\t\tnewTags = append(newTags, Tag)\n\t}\n\n\t// Need to manually copy data because there is no automatic method to convert\n\t// from VirtualChassis to WritableVirtualChassis\n\tvcUpdateData := models.WritableVirtualChassis{\n\t\tID:          vcData.ID,\n\t\tDescription: vcData.Description,\n\t\tDomain:      vcData.Domain,\n\t\tName:        vcData.Name,\n\t\tComments:    vcData.Comments,\n\t\tTags:        newTags,\n\t\tMaster:      master,\n\t}\n\n\t_, err = api.Dcim.DcimVirtualChassisUpdate(dcim.NewDcimVirtualChassisUpdateParams().WithID(id).WithData(&vcUpdateData), nil)\n\treturn err\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_chassis_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/dcim\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc TestAccNetboxVirtualChassis_basic(t *testing.T) {\n\ttestSlug := \"virtual_chassis\"\n\ttestName := testAccGetTestName(testSlug)\n\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckVirtualChassisDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"tag_a\" {\n\tname = \"[%[1]s_a]\"\n\tcolor_hex = \"123456\"\n}\nresource \"netbox_virtual_chassis\" \"test\" {\n\tname = \"%[1]s\"\n\tdomain = \"domain\"\n\tdescription = \"description\"\n\tcomments = \"comment\"\n\ttags = [netbox_tag.tag_a.name]\n}\n\t\t\t\t`, testName),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"tag_a\" {\n\tname = \"[%[1]s_a]\"\n\tcolor_hex = \"123456\"\n}\nresource \"netbox_virtual_chassis\" \"test\" {\n\tname = \"%[1]s_updated\"\n\tdomain = \"domain_updated\"\n\tdescription = \"description updated\"\n\tcomments = \"comment updated\"\n\ttags = [netbox_tag.tag_a.name]\n}\n\t\t\t\t`, testName),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_virtual_chassis.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckVirtualChassisDestroy(s *terraform.State) error {\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each virtual machine\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_virtual_chassis\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := dcim.NewDcimVirtualChassisReadParams().WithID(stateID)\n\t\t_, err := conn.Dcim.DcimVirtualChassisRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"virtual chassis (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*dcim.DcimVirtualChassisReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_disk.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxVirtualDisks() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxVirtualDisksCreate,\n\t\tReadContext:   resourceNetboxVirtualDisksRead,\n\t\tUpdateContext: resourceNetboxVirtualDisksUpdate,\n\t\tDeleteContext: resourceNetboxVirtualDisksDelete,\n\t\tDescription: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/models/virtualization/virtualdisk/):\n\n\t\t> A virtual disk is used to model discrete virtual hard disks assigned to virtual machines.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"size_mb\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"virtual_machine_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t\tSchemaVersion: 1,\n\t\tStateUpgraders: []schema.StateUpgrader{\n\t\t\t{\n\t\t\t\tType:    resourceNetboxVirtualDiskResourceV0().CoreConfigSchema().ImpliedType(),\n\t\t\t\tUpgrade: resourceNetboxVirtualDiskStateUpgradeV0,\n\t\t\t\tVersion: 0,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVirtualDisksCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tsize := d.Get(\"size_mb\").(int)\n\tvirtualMachineID := d.Get(\"virtual_machine_id\").(int)\n\n\tdata := models.WritableVirtualDisk{\n\t\tName:           &name,\n\t\tSize:           int64ToPtr(int64(size)),\n\t\tVirtualMachine: int64ToPtr(int64(virtualMachineID)),\n\t}\n\n\tdescriptionValue, ok := d.GetOk(\"description\")\n\tif ok {\n\t\tdescription := descriptionValue.(string)\n\t\tdata.Description = description\n\t}\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tparams := virtualization.NewVirtualizationVirtualDisksCreateParams().WithData(&data)\n\n\tres, err := api.Virtualization.VirtualizationVirtualDisksCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVirtualDisksRead(ctx, d, m)\n}\n\nfunc resourceNetboxVirtualDisksRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := virtualization.NewVirtualizationVirtualDisksReadParams().WithID(id)\n\n\tres, err := api.Virtualization.VirtualizationVirtualDisksRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationVirtualDisksReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\tVirtualDisks := res.GetPayload()\n\n\td.Set(\"name\", VirtualDisks.Name)\n\td.Set(\"description\", VirtualDisks.Description)\n\n\tif VirtualDisks.Size != nil {\n\t\td.Set(\"size_mb\", *VirtualDisks.Size)\n\t}\n\tif VirtualDisks.VirtualMachine != nil {\n\t\td.Set(\"virtual_machine_id\", VirtualDisks.VirtualMachine.ID)\n\t}\n\n\tcf := getCustomFields(res.GetPayload().CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\tapi.readTags(d, VirtualDisks.Tags)\n\treturn nil\n}\n\nfunc resourceNetboxVirtualDisksUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableVirtualDisk{}\n\n\tname := d.Get(\"name\").(string)\n\tsize := int64(d.Get(\"size_mb\").(int))\n\tvirtualMachineID := int64(d.Get(\"virtual_machine_id\").(int))\n\n\tdata.Name = &name\n\tdata.Size = &size\n\tdata.VirtualMachine = &virtualMachineID\n\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tif d.HasChanges(\"description\") {\n\t\t// check if description is set\n\t\tif descriptionValue, ok := d.GetOk(\"description\"); ok {\n\t\t\tdata.Description = descriptionValue.(string)\n\t\t} else {\n\t\t\tdata.Description = \" \"\n\t\t}\n\t}\n\n\tparams := virtualization.NewVirtualizationVirtualDisksUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Virtualization.VirtualizationVirtualDisksUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn resourceNetboxVirtualDisksRead(ctx, d, m)\n}\n\nfunc resourceNetboxVirtualDisksDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationVirtualDisksDeleteParams().WithID(id)\n\n\t_, err := api.Virtualization.VirtualizationVirtualDisksDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationVirtualDisksDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_disk_migrate_v0.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxVirtualDiskResourceV0() *schema.Resource {\n\treturn &schema.Resource{\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"size_mb\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"virtual_machine_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\ttagsKey:         tagsSchema,\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVirtualDiskStateUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {\n\tv, ok := rawState[\"size_gb\"].(float64)\n\tif !ok {\n\t\tlog.Printf(\"[DEBUG] disk size before migration isnt float64: %#v\\n but a %T\", rawState[\"size_gb\"], rawState[\"size_gb\"])\n\t\trawState[\"size_mb\"] = float64(0)\n\t\tdelete(rawState, \"size_gb\")\n\t\treturn rawState, nil\n\t}\n\n\tlog.Printf(\"[DEBUG] disk size in GB before migration: %#v\\n\", rawState[\"size_gb\"])\n\n\t// set new disk size\n\trawState[\"size_mb\"] = v * 1000\n\tlog.Printf(\"[DEBUG] disk size in MB after migration: %#v\\n\", rawState[\"size_mb\"])\n\n\tdelete(rawState, \"size_gb\")\n\n\treturn rawState, nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_disk_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc TestAccNetboxVirtualDisk_basic(t *testing.T) {\n\ttestSlug := \"virtual_disk\"\n\ttestName := testAccGetTestName(testSlug)\n\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckVirtualDiskDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"tag_a\" {\n\tname = \"[%[1]s_a]\"\n\tcolor_hex = \"123456\"\n}\nresource \"netbox_site\" \"test\" {\n\tname = \"%[1]s\"\n\tstatus = \"active\"\n}\nresource \"netbox_virtual_machine\" \"test\" {\n\tname = \"%[1]s\"\n\tsite_id = netbox_site.test.id\n}\nresource \"netbox_virtual_disk\" \"test\" {\n\tname = \"%[1]s\"\n\tdescription = \"description\"\n\tsize_mb = 30\n\tvirtual_machine_id = netbox_virtual_machine.test.id\n\ttags = [netbox_tag.tag_a.name]\n}\n\t\t\t\t`, testName),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"tag_a\" {\n\tname = \"[%[1]s_a]\"\n\tcolor_hex = \"123456\"\n}\nresource \"netbox_site\" \"test\" {\n\tname = \"%[1]s\"\n\tstatus = \"active\"\n}\nresource \"netbox_virtual_machine\" \"test\" {\n\tname = \"%[1]s\"\n\tsite_id = netbox_site.test.id\n}\nresource \"netbox_virtual_disk\" \"test\" {\n\tname = \"%[1]s_updated\"\n\tdescription = \"description updated\"\n\tsize_mb = 60\n\tvirtual_machine_id = netbox_virtual_machine.test.id\n\ttags = [netbox_tag.tag_a.name]\n}\n\t\t\t\t`, testName),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_virtual_disk.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckVirtualDiskDestroy(s *terraform.State) error {\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each virtual machine\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_virtual_disk\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := virtualization.NewVirtualizationVirtualDisksReadParams().WithID(stateID)\n\t\t_, err := conn.Virtualization.VirtualizationVirtualDisksRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"virtual disk (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif errresp, ok := err.(*virtualization.VirtualizationVirtualDisksReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_machine.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/diag\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxVirtualMachineStatusOptions = []string{\"offline\", \"active\", \"planned\", \"staged\", \"failed\", \"decommissioning\"}\n\nfunc resourceNetboxVirtualMachine() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreateContext: resourceNetboxVirtualMachineCreate,\n\t\tReadContext:   resourceNetboxVirtualMachineRead,\n\t\tUpdateContext: resourceNetboxVirtualMachineUpdate,\n\t\tDeleteContext: resourceNetboxVirtualMachineDelete,\n\n\t\tDescription: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#virtual-machines):\n\n> A virtual machine is a virtualized compute instance. These behave in NetBox very similarly to device objects, but without any physical attributes. For example, a VM may have interfaces assigned to it with IP addresses and VLANs, however its interfaces cannot be connected via cables (because they are virtual). Each VM may also define its compute, memory, and storage resources as well.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"cluster_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"site_id\", \"cluster_id\"},\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"platform_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"site_id\", \"cluster_id\"},\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"memory_mb\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"vcpus\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"disk_size_mb\": {\n\t\t\t\tType:        schema.TypeInt,\n\t\t\t\tOptional:    true,\n\t\t\t\tComputed:    true,\n\t\t\t\tDescription: \"The disk size in MB. When virtual disks are attached to this VM, NetBox automatically computes this as the aggregate of those disks and rejects manual values. In that case, omit this field from the configuration and let it be computed.\",\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxVirtualMachineStatusOptions, false),\n\t\t\t\tDefault:      \"active\",\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxVirtualMachineStatusOptions),\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"primary_ipv4\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"primary_ipv6\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"local_context_data\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"This is best managed through the use of `jsonencode` and a map of settings.\",\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t\tSchemaVersion: 2,\n\t\tStateUpgraders: []schema.StateUpgrader{\n\t\t\t{\n\t\t\t\tType:    resourceNetboxVirtualMachineResourceV0().CoreConfigSchema().ImpliedType(),\n\t\t\t\tUpgrade: resourceNetboxVirtualMachineStateUpgradeV0,\n\t\t\t\tVersion: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:    resourceNetboxVirtualMachineResourceV1().CoreConfigSchema().ImpliedType(),\n\t\t\t\tUpgrade: resourceNetboxVirtualMachineStateUpgradeV1,\n\t\t\t\tVersion: 1,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVirtualMachineCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\n\tdata := models.WritableVirtualMachineWithConfigContext{\n\t\tName: &name,\n\t}\n\n\tclusterIDValue, ok := d.GetOk(\"cluster_id\")\n\tif ok {\n\t\tclusterID := int64(clusterIDValue.(int))\n\t\tdata.Cluster = &clusterID\n\t}\n\n\tsiteIDValue, ok := d.GetOk(\"site_id\")\n\tif ok {\n\t\tsiteID := int64(siteIDValue.(int))\n\t\tdata.Site = &siteID\n\t}\n\n\tdata.Comments = d.Get(\"comments\").(string)\n\tdata.Description = d.Get(\"description\").(string)\n\n\tvcpusValue, ok := d.GetOk(\"vcpus\")\n\tif ok {\n\t\tvcpus := vcpusValue.(float64)\n\t\tdata.Vcpus = &vcpus\n\t}\n\n\tmemoryMbValue, ok := d.GetOk(\"memory_mb\")\n\tif ok {\n\t\tmemoryMb := int64(memoryMbValue.(int))\n\t\tdata.Memory = &memoryMb\n\t}\n\n\tdiskSizeValue, ok := d.GetOk(\"disk_size_mb\")\n\tif ok {\n\t\tdiskSize := int64(diskSizeValue.(int))\n\t\tdata.Disk = &diskSize\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\ttenantID := int64(tenantIDValue.(int))\n\t\tdata.Tenant = &tenantID\n\t}\n\n\tdeviceIDValue, ok := d.GetOk(\"device_id\")\n\tif ok {\n\t\tdeviceID := int64(deviceIDValue.(int))\n\t\tdata.Device = &deviceID\n\t}\n\n\tplatformIDValue, ok := d.GetOk(\"platform_id\")\n\tif ok {\n\t\tplatformID := int64(platformIDValue.(int))\n\t\tdata.Platform = &platformID\n\t}\n\n\troleIDValue, ok := d.GetOk(\"role_id\")\n\tif ok {\n\t\troleID := int64(roleIDValue.(int))\n\t\tdata.Role = &roleID\n\t}\n\n\tlocalContextValue, ok := d.GetOk(\"local_context_data\")\n\tif ok {\n\t\tvar jsonObj any\n\t\tlocalContextBA := []byte(localContextValue.(string))\n\t\tif err := json.Unmarshal(localContextBA, &jsonObj); err == nil {\n\t\t\tdata.LocalContextData = jsonObj\n\t\t}\n\t}\n\n\tdata.Status = d.Get(\"status\").(string)\n\n\ttags, err := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tdata.Tags = tags\n\tct, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = ct\n\t}\n\n\tparams := virtualization.NewVirtualizationVirtualMachinesCreateParams().WithData(&data)\n\n\tres, err := api.Virtualization.VirtualizationVirtualMachinesCreate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVirtualMachineRead(ctx, d, m)\n}\n\nfunc resourceNetboxVirtualMachineRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := virtualization.NewVirtualizationVirtualMachinesReadParams().WithID(id)\n\n\tres, err := api.Virtualization.VirtualizationVirtualMachinesRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationVirtualMachinesReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\n\tvm := res.GetPayload()\n\n\td.Set(\"name\", vm.Name)\n\n\tif vm.Cluster != nil {\n\t\td.Set(\"cluster_id\", vm.Cluster.ID)\n\t} else {\n\t\td.Set(\"cluster_id\", nil)\n\t}\n\n\tif vm.PrimaryIp4 != nil {\n\t\td.Set(\"primary_ipv4\", vm.PrimaryIp4.ID)\n\t} else {\n\t\td.Set(\"primary_ipv4\", nil)\n\t}\n\n\tif vm.PrimaryIp6 != nil {\n\t\td.Set(\"primary_ipv6\", vm.PrimaryIp6.ID)\n\t} else {\n\t\td.Set(\"primary_ipv6\", nil)\n\t}\n\n\tif vm.Tenant != nil {\n\t\td.Set(\"tenant_id\", vm.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tif vm.Device != nil {\n\t\td.Set(\"device_id\", vm.Device.ID)\n\t} else {\n\t\td.Set(\"device_id\", nil)\n\t}\n\n\tif vm.Role != nil {\n\t\td.Set(\"role_id\", vm.Role.ID)\n\t} else {\n\t\td.Set(\"role_id\", nil)\n\t}\n\n\tif vm.Platform != nil {\n\t\td.Set(\"platform_id\", vm.Platform.ID)\n\t} else {\n\t\td.Set(\"platform_id\", nil)\n\t}\n\n\tif vm.Role != nil {\n\t\td.Set(\"role_id\", vm.Role.ID)\n\t} else {\n\t\td.Set(\"role_id\", nil)\n\t}\n\n\tif vm.Site != nil {\n\t\td.Set(\"site_id\", vm.Site.ID)\n\t} else {\n\t\td.Set(\"site_id\", nil)\n\t}\n\n\tif vm.LocalContextData != nil {\n\t\tif jsonArr, err := json.Marshal(vm.LocalContextData); err == nil {\n\t\t\td.Set(\"local_context_data\", string(jsonArr))\n\t\t}\n\t} else {\n\t\td.Set(\"local_context_data\", nil)\n\t}\n\n\td.Set(\"comments\", vm.Comments)\n\td.Set(\"description\", vm.Description)\n\tvcpus := vm.Vcpus\n\tif vcpus != nil {\n\t\td.Set(\"vcpus\", vm.Vcpus)\n\t} else {\n\t\td.Set(\"vcpus\", nil)\n\t}\n\td.Set(\"memory_mb\", vm.Memory)\n\td.Set(\"disk_size_mb\", vm.Disk)\n\tif vm.Status != nil {\n\t\td.Set(\"status\", vm.Status.Value)\n\t} else {\n\t\td.Set(\"status\", nil)\n\t}\n\tapi.readTags(d, vm.Tags)\n\n\tcf := getCustomFields(vm.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\n\treturn diags\n}\n\nfunc resourceNetboxVirtualMachineUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableVirtualMachineWithConfigContext{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tclusterIDValue, ok := d.GetOk(\"cluster_id\")\n\tif ok {\n\t\tclusterID := int64(clusterIDValue.(int))\n\t\tdata.Cluster = &clusterID\n\t}\n\n\tsiteIDValue, ok := d.GetOk(\"site_id\")\n\tif ok {\n\t\tsiteID := int64(siteIDValue.(int))\n\t\tdata.Site = &siteID\n\t}\n\n\ttenantIDValue, ok := d.GetOk(\"tenant_id\")\n\tif ok {\n\t\ttenantID := int64(tenantIDValue.(int))\n\t\tdata.Tenant = &tenantID\n\t}\n\n\tdeviceIDValue, ok := d.GetOk(\"device_id\")\n\tif ok {\n\t\tdeviceID := int64(deviceIDValue.(int))\n\t\tdata.Device = &deviceID\n\t}\n\n\tplatformIDValue, ok := d.GetOk(\"platform_id\")\n\tif ok {\n\t\tplatformID := int64(platformIDValue.(int))\n\t\tdata.Platform = &platformID\n\t}\n\n\troleIDValue, ok := d.GetOk(\"role_id\")\n\tif ok {\n\t\troleID := int64(roleIDValue.(int))\n\t\tdata.Role = &roleID\n\t}\n\n\tmemoryMbValue, ok := d.GetOk(\"memory_mb\")\n\tif ok {\n\t\tmemoryMb := int64(memoryMbValue.(int))\n\t\tdata.Memory = &memoryMb\n\t}\n\n\tvcpusValue, ok := d.GetOk(\"vcpus\")\n\tif ok {\n\t\tvcpus := vcpusValue.(float64)\n\t\tdata.Vcpus = &vcpus\n\t}\n\n\t// Only send disk_size_mb when explicitly set in config. When virtual disks\n\t// are attached, NetBox computes this as their aggregate and rejects any\n\t// value that does not match — including stale prior-state values.\n\tif !d.GetRawConfig().GetAttr(\"disk_size_mb\").IsNull() {\n\t\tdiskSize := int64(d.Get(\"disk_size_mb\").(int))\n\t\tdata.Disk = &diskSize\n\t}\n\n\tprimaryIP4Value, ok := d.GetOk(\"primary_ipv4\")\n\tif ok {\n\t\tprimaryIP4 := int64(primaryIP4Value.(int))\n\t\tdata.PrimaryIp4 = &primaryIP4\n\t}\n\n\tprimaryIP6Value, ok := d.GetOk(\"primary_ipv6\")\n\tif ok {\n\t\tprimaryIP6 := int64(primaryIP6Value.(int))\n\t\tdata.PrimaryIp6 = &primaryIP6\n\t}\n\n\tlocalContextValue, ok := d.GetOk(\"local_context_data\")\n\tif ok {\n\t\tvar jsonObj any\n\t\tlocalContextBA := []byte(localContextValue.(string))\n\t\tif err := json.Unmarshal(localContextBA, &jsonObj); err == nil {\n\t\t\tdata.LocalContextData = jsonObj\n\t\t}\n\t}\n\n\ttags, err := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\tdata.Tags = tags\n\tcf, ok := d.GetOk(customFieldsKey)\n\tif ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tif d.HasChanges(\"comments\") {\n\t\t// check if comment is set\n\t\tif commentsValue, ok := d.GetOk(\"comments\"); ok {\n\t\t\tdata.Comments = commentsValue.(string)\n\t\t} else {\n\t\t\tdata.Comments = \" \"\n\t\t}\n\t}\n\tif d.HasChanges(\"description\") {\n\t\t// check if description is set\n\t\tif descriptionValue, ok := d.GetOk(\"description\"); ok {\n\t\t\tdata.Description = descriptionValue.(string)\n\t\t} else {\n\t\t\tdata.Description = \" \"\n\t\t}\n\t}\n\n\t// if d.HasChanges(\"status\") {\n\tif status, ok := d.GetOk(\"status\"); ok {\n\t\tdata.Status = status.(string)\n\t}\n\t//}\n\n\tparams := virtualization.NewVirtualizationVirtualMachinesUpdateParams().WithID(id).WithData(&data)\n\n\t_, err = api.Virtualization.VirtualizationVirtualMachinesUpdate(params, nil)\n\tif err != nil {\n\t\treturn diag.FromErr(err)\n\t}\n\n\treturn resourceNetboxVirtualMachineRead(ctx, d, m)\n}\n\nfunc resourceNetboxVirtualMachineDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {\n\tapi := m.(*providerState)\n\n\tvar diags diag.Diagnostics\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := virtualization.NewVirtualizationVirtualMachinesDeleteParams().WithID(id)\n\n\t_, err := api.Virtualization.VirtualizationVirtualMachinesDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*virtualization.VirtualizationVirtualMachinesDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn diag.FromErr(err)\n\t}\n\treturn diags\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_machine_migrate_v0.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"strconv\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxVirtualMachineResourceV0() *schema.Resource {\n\treturn &schema.Resource{\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"cluster_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"platform_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"memory_mb\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"vcpus\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"disk_size_gb\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"primary_ipv4\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t},\n\t}\n}\nfunc resourceNetboxVirtualMachineStateUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {\n\tv, ok := rawState[\"vcpus\"]\n\tif !ok {\n\t\treturn rawState, nil\n\t}\n\n\ts, ok := v.(string)\n\tif !ok {\n\t\t// since the provider was already released without this state migration, we have to accept that this field already contains non-string content\n\t\treturn rawState, nil\n\t}\n\n\tlog.Printf(\"[DEBUG] vcpus before migration: %#v\", rawState[\"vcpus\"])\n\n\tf, err := strconv.ParseFloat(s, 64)\n\tif err == nil {\n\t\trawState[\"vcpus\"] = f\n\t} else {\n\t\trawState[\"vcpus\"] = float64(0)\n\t\tlog.Printf(\"[DEBUG] Schema upgrade: vcpus has been migrated to %g\", f)\n\t}\n\n\tlog.Printf(\"[DEBUG] vcpus after migration: %#v\", rawState[\"vcpus\"])\n\treturn rawState, nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_machine_migrate_v0_test.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestResourceNetboxVirtualMachineStateUpgradeV0(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tstate    map[string]interface{}\n\t\texpected map[string]interface{}\n\t}{\n\t\t{\n\t\t\tname:     \"Empty\",\n\t\t\tstate:    map[string]interface{}{\"vcpus\": \"\"},\n\t\t\texpected: map[string]interface{}{\"vcpus\": float64(0)},\n\t\t},\n\t\t{\n\t\t\tname:     \"Zero\",\n\t\t\tstate:    map[string]interface{}{\"vcpus\": \"0\"},\n\t\t\texpected: map[string]interface{}{\"vcpus\": float64(0)},\n\t\t},\n\t\t{\n\t\t\tname:     \"NonZero\",\n\t\t\tstate:    map[string]interface{}{\"vcpus\": \"123\"},\n\t\t\texpected: map[string]interface{}{\"vcpus\": float64(123)},\n\t\t},\n\t\t{\n\t\t\tname:     \"Float\",\n\t\t\tstate:    map[string]interface{}{\"vcpus\": \"4.5\"},\n\t\t\texpected: map[string]interface{}{\"vcpus\": 4.5},\n\t\t},\n\t\t{\n\t\t\tname:     \"Invalid\",\n\t\t\tstate:    map[string]interface{}{\"vcpus\": \"foo\"},\n\t\t\texpected: map[string]interface{}{\"vcpus\": float64(0)},\n\t\t},\n\t\t{\n\t\t\tname:     \"FloatAsFloat\",\n\t\t\tstate:    map[string]interface{}{\"vcpus\": 4.5},\n\t\t\texpected: map[string]interface{}{\"vcpus\": 4.5},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, err := resourceNetboxVirtualMachineStateUpgradeV0(context.Background(), tt.state, nil)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"error migrating state: %s\", err)\n\t\t\t}\n\t\t\tif !reflect.DeepEqual(tt.expected, actual) {\n\t\t\t\tt.Fatalf(\"\\n\\nexpected:\\n\\n%#v\\n\\ngot:\\n\\n%#v\\n\\n\", tt.expected, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_machine_migrate_v1.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc resourceNetboxVirtualMachineResourceV1() *schema.Resource {\n\treturn &schema.Resource{\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"cluster_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"site_id\", \"cluster_id\"},\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"device_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"platform_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"site_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tAtLeastOneOf: []string{\"site_id\", \"cluster_id\"},\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"memory_mb\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"vcpus\": {\n\t\t\t\tType:     schema.TypeFloat,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"disk_size_gb\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  \"active\",\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t\t\"primary_ipv4\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"primary_ipv6\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tComputed: true,\n\t\t\t},\n\t\t\t\"local_context_data\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"This is best managed through the use of `jsonencode` and a map of settings.\",\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t},\n\t}\n}\nfunc resourceNetboxVirtualMachineStateUpgradeV1(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {\n\tv, ok := rawState[\"disk_size_gb\"].(float64)\n\tif !ok {\n\t\tlog.Printf(\"[DEBUG] disk size before migration isnt float64: %#v\\n but a %T\", rawState[\"disk_size_gb\"], rawState[\"disk_size_gb\"])\n\t\trawState[\"disk_size_mb\"] = float64(0)\n\t\tdelete(rawState, \"disk_size_gb\")\n\t\treturn rawState, nil\n\t}\n\n\tlog.Printf(\"[DEBUG] disk size in GB before migration: %#v\\n\", rawState[\"disk_size_gb\"])\n\n\t// set new disk size\n\trawState[\"disk_size_mb\"] = v * 1000\n\tlog.Printf(\"[DEBUG] disk size in MB after migration: %#v\\n\", rawState[\"disk_size_mb\"])\n\n\tdelete(rawState, \"disk_size_gb\")\n\n\treturn rawState, nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_machine_migrate_v1_test.go",
    "content": "package netbox\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestResourceNetboxVirtualMachineStateUpgradeV1(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tstate    map[string]interface{}\n\t\texpected map[string]interface{}\n\t}{\n\t\t{\n\t\t\tname:     \"Zero\",\n\t\t\tstate:    map[string]interface{}{\"disk_size_gb\": float64(0)},\n\t\t\texpected: map[string]interface{}{\"disk_size_mb\": float64(0)},\n\t\t},\n\t\t{\n\t\t\tname:     \"NonZero\",\n\t\t\tstate:    map[string]interface{}{\"disk_size_gb\": float64(123)},\n\t\t\texpected: map[string]interface{}{\"disk_size_mb\": float64(123000)},\n\t\t},\n\t\t{\n\t\t\tname:     \"Invalid\",\n\t\t\tstate:    map[string]interface{}{\"disk_size_gb\": \"foo\"},\n\t\t\texpected: map[string]interface{}{\"disk_size_mb\": float64(0)},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, err := resourceNetboxVirtualMachineStateUpgradeV1(context.Background(), tt.state, nil)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"error migrating state: %s\", err)\n\t\t\t}\n\t\t\tif !reflect.DeepEqual(tt.expected, actual) {\n\t\t\t\tt.Fatalf(\"\\n\\nexpected:\\n\\n%#v\\n\\ngot:\\n\\n%#v\\n\\n\", tt.expected, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "netbox/resource_netbox_virtual_machine_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/virtualization\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc testAccNetboxVirtualMachineFullDependencies(testName string) string {\n\ttestSlug := \"device_type\"\n\trandomSlug := testAccGetTestName(testSlug)\n\n\treturn fmt.Sprintf(`\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  site_id = netbox_site.test.id\n}\n\nresource \"netbox_device_role\" \"test\" {\n  name = \"%[1]s\"\n  color_hex = \"123456\"\n}\n\nresource \"netbox_platform\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_tag\" \"test_b\" {\n  name = \"%[1]sb\"\n}\n\nresource \"netbox_manufacturer\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_device_type\" \"test\" {\n  model = \"%[1]s\"\n  slug = \"%[2]s\"\n  part_number = \"%[2]s\"\n  manufacturer_id = netbox_manufacturer.test.id\n}\n\nresource \"netbox_device\" \"test\" {\n  name = \"%[1]s\"\n  role_id = netbox_device_role.test.id\n  device_type_id = netbox_device_type.test.id\n  site_id = netbox_site.test.id\n  cluster_id = netbox_cluster.test.id\n}\n`, testName, randomSlug)\n}\n\nfunc testAccNetboxVirtualMachineSiteClusterDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_site\" \"test\" {\n  name = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n  site_id = netbox_site.test.id\n}\n`, testName)\n}\n\nfunc TestAccNetboxVirtualMachine_SiteOnly(t *testing.T) {\n\ttestSlug := \"vm_site\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckVirtualMachineDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineSiteClusterDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"only_site\" {\n  name = \"%s\"\n  site_id = netbox_site.test.id\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.only_site\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.only_site\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_virtual_machine.only_site\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVirtualMachine_ClusterWithoutSite(t *testing.T) {\n\ttestSlug := \"vm_clstrnosite\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckVirtualMachineDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_cluster_type\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_cluster\" \"test\" {\n  name = \"%[1]s\"\n  cluster_type_id = netbox_cluster_type.test.id\n}\n\nresource \"netbox_virtual_machine\" \"cluster_without_site\" {\n  name = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.cluster_without_site\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.cluster_without_site\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_virtual_machine.cluster_without_site\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVirtualMachine_basic(t *testing.T) {\n\ttestSlug := \"vm_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckVirtualMachineDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  comments = \"thisisacomment\"\n  description = \"thisisadescription\"\n  memory_mb = 1024\n  disk_size_mb = 256\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  platform_id = netbox_platform.test.id\n  device_id = netbox_device.test.id\n  vcpus = 4\n  status = \"active\"\n  tags = [netbox_tag.test_a.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"device_id\", \"netbox_device.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"description\", \"thisisadescription\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"memory_mb\", \"1024\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"vcpus\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"disk_size_mb\", \"256\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  site_id = netbox_site.test.id\n  comments = \"thisisacomment\"\n  description = \"thisisadescription\"\n  memory_mb = 1024\n  disk_size_mb = 256\n  tenant_id = netbox_tenant.test.id\n  role_id = netbox_device_role.test.id\n  platform_id = netbox_platform.test.id\n  vcpus = 4\n  status = \"active\"\n  tags = [netbox_tag.test_a.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"platform_id\", \"netbox_platform.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"role_id\", \"netbox_device_role.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"comments\", \"thisisacomment\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"description\", \"thisisadescription\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"memory_mb\", \"1024\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"vcpus\", \"4\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"disk_size_mb\", \"256\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.0\", testName+\"a\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  tenant_id = netbox_tenant.test.id\n  platform_id = netbox_platform.test.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"vcpus\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"memory_mb\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"description\", \"\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_virtual_machine.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVirtualMachine_fractionalVcpu(t *testing.T) {\n\ttestSlug := \"vm_fracVcpu\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckVirtualMachineDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  vcpus = 2.50\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"vcpus\", \"2.5\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  vcpus = 4\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"vcpus\", \"4\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_virtual_machine.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckVirtualMachineDestroy(s *terraform.State) error {\n\t// retrieve the connection established in Provider configuration\n\tconn := testAccProvider.Meta().(*providerState)\n\n\t// loop through the resources in state, verifying each virtual machine\n\t// is destroyed\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_virtual_machine\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Retrieve our virtual machine by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\tparams := virtualization.NewVirtualizationVirtualMachinesReadParams().WithID(stateID)\n\t\t_, err := conn.Virtualization.VirtualizationVirtualMachinesRead(params, nil)\n\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"virtual machine (%s) still exists\", rs.Primary.ID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif errresp, ok := err.(*virtualization.VirtualizationVirtualMachinesReadDefault); ok {\n\t\t\t\terrorcode := errresp.Code()\n\t\t\t\tif errorcode == 404 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc TestAccNetboxVirtualMachine_tags(t *testing.T) {\n\ttestSlug := \"vm_tags\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  tags = [netbox_tag.test_a.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_virtual_machine.test\", \"cluster_id\", \"netbox_cluster.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.#\", \"1\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n  tags = [netbox_tag.test_a.name, netbox_tag.test_b.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.#\", \"2\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name = \"%s\"\n  cluster_id = netbox_cluster.test.id\n  site_id = netbox_site.test.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVirtualMachine_customFields(t *testing.T) {\n\ttestSlug := \"vm_cf\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_custom_field\" \"test\" {\n\tname          = \"custom_field\"\n\ttype          = \"text\"\n\tcontent_types = [\"virtualization.virtualmachine\"]\n}\nresource \"netbox_virtual_machine\" \"test\" {\n  name          = \"%[1]s\"\n  cluster_id    = netbox_cluster.test.id\n  site_id       = netbox_site.test.id\n  custom_fields = {\"${netbox_custom_field.test.name}\" = \"76\"}\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"custom_fields.custom_field\", \"76\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVirtualMachine_localContext(t *testing.T) {\n\ttestSlug := \"vm_lc\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.Test(t, resource.TestCase{\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tProviders: testAccProviders,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name               = \"%[1]s\"\n  cluster_id         = netbox_cluster.test.id\n  site_id            = netbox_site.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name               = \"%[1]s_foo\"\n  cluster_id         = netbox_cluster.test.id\n  site_id            = netbox_site.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value\"})\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name               = \"%[1]s\"\n  cluster_id         = netbox_cluster.test.id\n  site_id            = netbox_site.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value\"})\n  }`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name               = \"%[1]s\"\n  cluster_id         = netbox_cluster.test.id\n  site_id            = netbox_site.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value_2\"})\n  }`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value_2\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name               = \"%[1]s\"\n  cluster_id         = netbox_cluster.test.id\n  site_id            = netbox_site.test.id\n  local_context_data = jsonencode({})\n  }`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name               = \"%[1]s\"\n  cluster_id         = netbox_cluster.test.id\n  site_id            = netbox_site.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value_2\"})\n  }`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value_2\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name               = \"%[1]s\"\n  cluster_id         = netbox_cluster.test.id\n  site_id            = netbox_site.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value_2\",\"test_string\"=\"broken\"})\n  }`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value_2\\\",\\\"test_string\\\":\\\"broken\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name               = \"%[1]s\"\n  cluster_id         = netbox_cluster.test.id\n  site_id            = netbox_site.test.id\n  local_context_data = jsonencode({\"context_string\"=\"context_value_2\"})\n  }`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test\", \"local_context_data\", \"{\\\"context_string\\\":\\\"context_value_2\\\"}\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\n// TestAccNetboxVirtualMachine_diskSizeMb covers two scenarios:\n//\n//  1. No virtual disks: disk_size_mb is set explicitly in config, and the\n//     provider sends that value to NetBox without interference from state.\n//\n//  2. Virtual disks attached: disk_size_mb is omitted from the VM config so\n//     the provider never sends it in PUT requests. NetBox does not automatically\n//     compute the aggregate when disks are attached to an existing VM; the field\n//     remains 0. The field is still readable (Computed) from state after refresh.\nfunc TestAccNetboxVirtualMachine_diskSizeMb(t *testing.T) {\n\ttestSlug := \"vm_disk\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tPreCheck:     func() { testAccPreCheck(t) },\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckVirtualMachineDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t// Step 1 – scenario 1: no virtual disks, disk_size_mb set explicitly.\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineSiteClusterDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test_scenario1\" {\n  name         = \"%[1]s_scenario1\"\n  cluster_id   = netbox_cluster.test.id\n  site_id      = netbox_site.test.id\n  disk_size_mb = 256\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test_scenario1\", \"disk_size_mb\", \"256\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Step 2 – scenario 1 update: change disk_size_mb without virtual disks.\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineSiteClusterDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test_scenario1\" {\n  name         = \"%[1]s_scenario1\"\n  cluster_id   = netbox_cluster.test.id\n  site_id      = netbox_site.test.id\n  disk_size_mb = 512\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_virtual_machine.test_scenario1\", \"disk_size_mb\", \"512\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t// Step 3 – scenario 2: virtual disks attached, disk_size_mb omitted from VM\n\t\t\t// config so NetBox owns the aggregate; no 400 error from disk mismatch.\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineSiteClusterDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name       = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n  site_id    = netbox_site.test.id\n  # disk_size_mb intentionally omitted – managed by attached virtual disks\n}\n\nresource \"netbox_virtual_disk\" \"a\" {\n  name               = \"%[1]s_a\"\n  size_mb            = 100\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n\nresource \"netbox_virtual_disk\" \"b\" {\n  name               = \"%[1]s_b\"\n  size_mb            = 200\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t// Check that disk_size_mb is computed but not verified in state\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_virtual_machine.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"disk_size_mb\"},\n\t\t\t},\n\t\t\t// Step 4 – scenario 2 update: resize a disk; NetBox computes disk_size_mb\n\t\t\t// to the aggregate of the attached disks at the time of VM update (300).\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVirtualMachineSiteClusterDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_virtual_machine\" \"test\" {\n  name       = \"%[1]s\"\n  cluster_id = netbox_cluster.test.id\n  site_id    = netbox_site.test.id\n}\n\nresource \"netbox_virtual_disk\" \"a\" {\n  name               = \"%[1]s_a\"\n  size_mb            = 150\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n\nresource \"netbox_virtual_disk\" \"b\" {\n  name               = \"%[1]s_b\"\n  size_mb            = 200\n  virtual_machine_id = netbox_virtual_machine.test.id\n}\n`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t// Check that disk_size_mb is computed but not verified in state\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_virtual_machine.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"disk_size_mb\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_virtual_machine\", &resource.Sweeper{\n\t\tName:         \"netbox_virtual_machine\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := virtualization.NewVirtualizationVirtualMachinesListParams()\n\t\t\tres, err := api.Virtualization.VirtualizationVirtualMachinesList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, virtualMachine := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*virtualMachine.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := virtualization.NewVirtualizationVirtualMachinesDeleteParams().WithID(virtualMachine.ID)\n\t\t\t\t\t_, err := api.Virtualization.VirtualizationVirtualMachinesDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a virtual machine\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vlan.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxVlanStatusOptions = []string{\"active\", \"reserved\", \"deprecated\"}\n\nfunc resourceNetboxVlan() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxVlanCreate,\n\t\tRead:   resourceNetboxVlanRead,\n\t\tUpdate: resourceNetboxVlanUpdate,\n\t\tDelete: resourceNetboxVlanDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/vlans/#vlans):\n\n> A VLAN represents an isolated layer two domain, identified by a name and a numeric ID (1-4094) as defined in IEEE 802.1Q. VLANs are arranged into VLAN groups to define scope and to enforce uniqueness.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"vid\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tDefault:      \"active\",\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxVlanStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxVlanStatusOptions),\n\t\t\t},\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\n\t\t\t\"role_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\n\t\t\t\"site_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  \"\",\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVlanCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableVLAN{}\n\n\tname := d.Get(\"name\").(string)\n\tvid := int64(d.Get(\"vid\").(int))\n\tstatus := d.Get(\"status\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Name = &name\n\tdata.Vid = &vid\n\tdata.Status = status\n\tdata.Description = description\n\n\tif groupID, ok := d.GetOk(\"group_id\"); ok {\n\t\tdata.Group = int64ToPtr(int64(groupID.(int)))\n\t}\n\n\tif siteID, ok := d.GetOk(\"site_id\"); ok {\n\t\tdata.Site = int64ToPtr(int64(siteID.(int)))\n\t}\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\n\tif roleID, ok := d.GetOk(\"role_id\"); ok {\n\t\tdata.Role = int64ToPtr(int64(roleID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamVlansCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamVlansCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVlanRead(d, m)\n}\n\nfunc resourceNetboxVlanRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamVlansReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamVlansRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamVlansReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tvlan := res.GetPayload()\n\n\td.Set(\"name\", vlan.Name)\n\td.Set(\"vid\", vlan.Vid)\n\td.Set(\"description\", vlan.Description)\n\tapi.readTags(d, vlan.Tags)\n\n\tif vlan.Status != nil {\n\t\td.Set(\"status\", vlan.Status.Value)\n\t}\n\tif vlan.Group != nil {\n\t\td.Set(\"group_id\", vlan.Group.ID)\n\t}\n\tif vlan.Site != nil {\n\t\td.Set(\"site_id\", vlan.Site.ID)\n\t}\n\tif vlan.Tenant != nil {\n\t\td.Set(\"tenant_id\", vlan.Tenant.ID)\n\t}\n\tif vlan.Role != nil {\n\t\td.Set(\"role_id\", vlan.Role.ID)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxVlanUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableVLAN{}\n\tname := d.Get(\"name\").(string)\n\tvid := int64(d.Get(\"vid\").(int))\n\tstatus := d.Get(\"status\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tdata.Name = &name\n\tdata.Vid = &vid\n\tdata.Status = status\n\tdata.Description = description\n\n\tif groupID, ok := d.GetOk(\"group_id\"); ok {\n\t\tdata.Group = int64ToPtr(int64(groupID.(int)))\n\t}\n\n\tif siteID, ok := d.GetOk(\"site_id\"); ok {\n\t\tdata.Site = int64ToPtr(int64(siteID.(int)))\n\t}\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\n\tif roleID, ok := d.GetOk(\"role_id\"); ok {\n\t\tdata.Role = int64ToPtr(int64(roleID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamVlansUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Ipam.IpamVlansUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxVlanRead(d, m)\n}\n\nfunc resourceNetboxVlanDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamVlansDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamVlansDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamVlansDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vlan_group.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxVlanGroupScopeTypeOptions = []string{\"dcim.location\", \"dcim.site\", \"dcim.sitegroup\", \"dcim.region\", \"dcim.rack\", \"virtualization.cluster\", \"virtualization.clustergroup\"}\n\nfunc resourceNetboxVlanGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxVlanGroupCreate,\n\t\tRead:   resourceNetboxVlanGroupRead,\n\t\tUpdate: resourceNetboxVlanGroupUpdate,\n\t\tDelete: resourceNetboxVlanGroupDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):\n\n> A VLAN Group represents a collection of VLANs. Generally, these are limited by one of a number of scopes such as \"Site\" or \"Virtualization Cluster\".`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"scope_type\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxVlanGroupScopeTypeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxVlanGroupScopeTypeOptions),\n\t\t\t},\n\t\t\t\"scope_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tRequiredWith: []string{\"scope_type\"},\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  \"\",\n\t\t\t},\n\t\t\t\"vid_ranges\": {\n\t\t\t\tType: schema.TypeList,\n\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\tType: schema.TypeList,\n\t\t\t\t\tElem: &schema.Schema{\n\t\t\t\t\t\tType: schema.TypeInt,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVlanGroupCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.VLANGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tslug := d.Get(\"slug\").(string)\n\tdescription := d.Get(\"description\").(string)\n\tvidRanges := d.Get(\"vid_ranges\").([]interface{})\n\n\tvar result = make([][]int64, 0)\n\tfor _, v := range vidRanges {\n\t\tinner := v.([]interface{})\n\t\tpair := make([]int64, 2)\n\t\tpair[0] = int64(inner[0].(int))\n\t\tpair[1] = int64(inner[1].(int))\n\t\tresult = append(result, pair)\n\t}\n\tdata.VidRanges = result\n\n\tdata.Name = &name\n\tdata.Slug = &slug\n\tdata.Description = description\n\n\tif scopeType, ok := d.GetOk(\"scope_type\"); ok {\n\t\tdata.ScopeType = strToPtr(scopeType.(string))\n\t}\n\n\tif scopeID, ok := d.GetOk(\"scope_id\"); ok {\n\t\tdata.ScopeID = int64ToPtr(int64(scopeID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamVlanGroupsCreateParams().WithData(&data)\n\tres, err := api.Ipam.IpamVlanGroupsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVlanGroupRead(d, m)\n}\n\nfunc resourceNetboxVlanGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamVlanGroupsReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamVlanGroupsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamVlanGroupsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tvlanGroup := res.GetPayload()\n\n\td.Set(\"name\", vlanGroup.Name)\n\td.Set(\"slug\", vlanGroup.Slug)\n\td.Set(\"description\", vlanGroup.Description)\n\td.Set(\"vid_ranges\", vlanGroup.VidRanges)\n\tapi.readTags(d, vlanGroup.Tags)\n\n\tif vlanGroup.ScopeType != nil {\n\t\td.Set(\"scope_type\", vlanGroup.ScopeType)\n\t}\n\n\tif vlanGroup.ScopeID != nil {\n\t\td.Set(\"scope_id\", vlanGroup.ScopeID)\n\t}\n\n\treturn nil\n}\n\nfunc resourceNetboxVlanGroupUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.VLANGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tslug := d.Get(\"slug\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tvidRanges := d.Get(\"vid_ranges\").([]interface{})\n\n\tvar result = make([][]int64, 0)\n\tfor _, v := range vidRanges {\n\t\tinner := v.([]interface{})\n\t\tpair := make([]int64, 2)\n\t\tpair[0] = int64(inner[0].(int))\n\t\tpair[1] = int64(inner[1].(int))\n\t\tresult = append(result, pair)\n\t}\n\tdata.VidRanges = result\n\n\tdata.Name = &name\n\tdata.Slug = &slug\n\tdata.Description = description\n\n\tif scopeType, ok := d.GetOk(\"scope_type\"); ok {\n\t\tdata.ScopeType = strToPtr(scopeType.(string))\n\t}\n\n\tif scopeID, ok := d.GetOk(\"scope_id\"); ok {\n\t\tdata.ScopeID = int64ToPtr(int64(scopeID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tparams := ipam.NewIpamVlanGroupsUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Ipam.IpamVlanGroupsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn resourceNetboxVlanGroupRead(d, m)\n}\n\nfunc resourceNetboxVlanGroupDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamVlanGroupsDeleteParams().WithID(id)\n\t_, err := api.Ipam.IpamVlanGroupsDelete(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vlan_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxVlanGroupFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n`, testName)\n}\nfunc TestAccNetboxVlanGroup_basic(t *testing.T) {\n\ttestSlug := \"vlan_group_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVlanGroupFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vlan_group\" \"test_basic\" {\n  name       = \"%s\"\n  slug       = \"%s\"\n  vid_ranges  = [[1, 2], [3, 4]]\n  tags       = []\n}`, testName, testSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_basic\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_basic\", \"slug\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_basic\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_basic\", \"tags.#\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_basic\", \"vid_ranges.0.0\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_basic\", \"vid_ranges.0.1\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_basic\", \"vid_ranges.1.0\", \"3\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_basic\", \"vid_ranges.1.1\", \"4\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vlan_group.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVlanGroup_with_dependencies(t *testing.T) {\n\ttestSlug := \"vlan_group_with_dependencies\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestDescription := \"Test Description\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVlanGroupFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vlan_group\" \"test_with_dependencies\" {\n  name        = \"%s\"\n  slug        = \"%s\"\n  description = \"%s\"\n  scope_type  = \"dcim.site\"\n  scope_id    = netbox_site.test.id\n  vid_ranges  = [[1, 4094]]\n  tags        = [netbox_tag.test.name]\n}`, testName, testSlug, testDescription),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_with_dependencies\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_with_dependencies\", \"slug\", testSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_with_dependencies\", \"description\", testDescription),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_with_dependencies\", \"scope_type\", \"dcim.site\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vlan_group.test_with_dependencies\", \"scope_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_with_dependencies\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan_group.test_with_dependencies\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vlan_group.test_with_dependencies\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_vlan_group\", &resource.Sweeper{\n\t\tName:         \"netbox_vlan_group\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamVlanGroupsListParams()\n\t\t\tres, err := api.Ipam.IpamVlanGroupsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, vlan := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*vlan.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamVlanGroupsDeleteParams().WithID(vlan.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamVlanGroupsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a vlan group\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vlan_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxVlanFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_vlan_group\" \"test_group\" {\n  name       = \"%[1]s\"\n  slug       = \"%[1]s\"\n  scope_type = \"dcim.site\"\n  scope_id   = netbox_site.test.id\n  vid_ranges = [[1, 4094]]\n}\n`, testName)\n}\nfunc TestAccNetboxVlan_basic(t *testing.T) {\n\ttestSlug := \"vlan_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestVid := \"777\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVlanFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vlan\" \"test_basic\" {\n  name = \"%s\"\n  vid  = \"%s\"\n  tags = []\n}`, testName, testVid),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_basic\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_basic\", \"vid\", testVid),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_basic\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_basic\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_basic\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vlan.test_basic\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVlan_with_dependencies(t *testing.T) {\n\ttestSlug := \"vlan_with_dependencies\"\n\ttestName := testAccGetTestName(testSlug)\n\ttestVid := \"666\"\n\ttestDescription := \"Test Description\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVlanFullDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vlan\" \"test_with_dependencies\" {\n  name        = \"%s\"\n  vid         = \"%s\"\n  description = \"%s\"\n  status      = \"active\"\n  tenant_id   = netbox_tenant.test.id\n  site_id     = netbox_site.test.id\n  group_id    = netbox_vlan_group.test_group.id\n  tags        = [netbox_tag.test.name]\n}`, testName, testVid, testDescription),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_with_dependencies\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_with_dependencies\", \"vid\", testVid),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_with_dependencies\", \"description\", testDescription),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_with_dependencies\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vlan.test_with_dependencies\", \"group_id\", \"netbox_vlan_group.test_group\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vlan.test_with_dependencies\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vlan.test_with_dependencies\", \"site_id\", \"netbox_site.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_with_dependencies\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vlan.test_with_dependencies\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vlan.test_with_dependencies\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_vlan\", &resource.Sweeper{\n\t\tName:         \"netbox_vlan\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamVlansListParams()\n\t\t\tres, err := api.Ipam.IpamVlansList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, vlan := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*vlan.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamVlansDeleteParams().WithID(vlan.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamVlansDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a vlan\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vpn_tunnel.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/vpn\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nvar resourceNetboxVpnTunnelEncapsulationOptions = []string{\"ipsec-transport\", \"ipsec-tunnel\", \"ip-ip\", \"gre\"}\nvar resourceNetboxVpnTunnelStatusOptions = []string{\"planned\", \"active\", \"disabled\"}\n\nfunc resourceNetboxVpnTunnel() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxVpnTunnelCreate,\n\t\tRead:   resourceNetboxVpnTunnelRead,\n\t\tUpdate: resourceNetboxVpnTunnelUpdate,\n\t\tDelete: resourceNetboxVpnTunnelDelete,\n\n\t\tDescription: `:meta:subcategory:VPN Tunnels:From the [official documentation](https://docs.netbox.dev/en/stable/features/vpn-tunnels/):\n\n> NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"encapsulation\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: buildValidValueDescription(resourceNetboxVpnTunnelEncapsulationOptions),\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: buildValidValueDescription(resourceNetboxVpnTunnelStatusOptions),\n\t\t\t},\n\t\t\t\"tunnel_group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tunnel_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVpnTunnelCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableTunnel{}\n\n\tdata.Name = strToPtr(d.Get(\"name\").(string))\n\tdata.Encapsulation = strToPtr(d.Get(\"encapsulation\").(string))\n\tdata.Status = strToPtr(d.Get(\"status\").(string))\n\tdata.Group = int64ToPtr(int64(d.Get(\"tunnel_group_id\").(int)))\n\n\tdata.Description = getOptionalStr(d, \"description\", false)\n\tdata.Tenant = getOptionalInt(d, \"tenant_id\")\n\tdata.TunnelID = getOptionalInt(d, \"tunnel_id\")\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tparams := vpn.NewVpnTunnelsCreateParams().WithData(&data)\n\n\tres, err := api.Vpn.VpnTunnelsCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVpnTunnelRead(d, m)\n}\n\nfunc resourceNetboxVpnTunnelRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := vpn.NewVpnTunnelsReadParams().WithID(id)\n\n\tres, err := api.Vpn.VpnTunnelsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*vpn.VpnTunnelsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\ttunnel := res.GetPayload()\n\td.Set(\"name\", tunnel.Name)\n\td.Set(\"encapsulation\", tunnel.Encapsulation.Value)\n\td.Set(\"status\", tunnel.Status.Value)\n\n\tif tunnel.Group != nil {\n\t\td.Set(\"tunnel_group_id\", tunnel.Group.ID)\n\t} else {\n\t\td.Set(\"tunnel_group_id\", nil)\n\t}\n\n\tif tunnel.Tenant != nil {\n\t\td.Set(\"tenant_id\", tunnel.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\td.Set(\"tunnel_id\", tunnel.TunnelID)\n\n\td.Set(\"description\", tunnel.Description)\n\n\tapi.readTags(d, res.GetPayload().Tags)\n\treturn nil\n}\n\nfunc resourceNetboxVpnTunnelUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableTunnel{}\n\n\tdata.Name = strToPtr(d.Get(\"name\").(string))\n\tdata.Encapsulation = strToPtr(d.Get(\"encapsulation\").(string))\n\tdata.Status = strToPtr(d.Get(\"status\").(string))\n\tdata.Group = int64ToPtr(int64(d.Get(\"tunnel_group_id\").(int)))\n\n\tdata.Description = getOptionalStr(d, \"description\", false)\n\tdata.Tenant = getOptionalInt(d, \"tenant_id\")\n\tdata.TunnelID = getOptionalInt(d, \"tunnel_id\")\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tparams := vpn.NewVpnTunnelsUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Vpn.VpnTunnelsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxVpnTunnelRead(d, m)\n}\n\nfunc resourceNetboxVpnTunnelDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := vpn.NewVpnTunnelsDeleteParams().WithID(id)\n\n\t_, err := api.Vpn.VpnTunnelsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*vpn.VpnTunnelsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vpn_tunnel_group.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/vpn\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxVpnTunnelGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxVpnTunnelGroupCreate,\n\t\tRead:   resourceNetboxVpnTunnelGroupRead,\n\t\tUpdate: resourceNetboxVpnTunnelGroupUpdate,\n\t\tDelete: resourceNetboxVpnTunnelGroupDelete,\n\n\t\tDescription: `:meta:subcategory:VPN Tunnels:From the [official documentation](https://docs.netbox.dev/en/stable/features/vpn-tunnels/):\n\n> NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVpnTunnelGroupCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.TunnelGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\tdata.Slug = &slug\n\n\tif description, ok := d.GetOk(\"description\"); ok {\n\t\tdata.Description = description.(string)\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := vpn.NewVpnTunnelGroupsCreateParams().WithData(&data)\n\n\tres, err := api.Vpn.VpnTunnelGroupsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVpnTunnelGroupRead(d, m)\n}\n\nfunc resourceNetboxVpnTunnelGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := vpn.NewVpnTunnelGroupsReadParams().WithID(id)\n\n\tres, err := api.Vpn.VpnTunnelGroupsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*vpn.VpnTunnelGroupsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\td.Set(\"name\", res.GetPayload().Name)\n\td.Set(\"slug\", res.GetPayload().Slug)\n\td.Set(\"description\", res.GetPayload().Description)\n\treturn nil\n}\n\nfunc resourceNetboxVpnTunnelGroupUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.TunnelGroup{}\n\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tvar slug string\n\t// Default slug to generated slug if not given\n\tif !slugOk {\n\t\tslug = getSlug(name)\n\t} else {\n\t\tslug = slugValue.(string)\n\t}\n\tdata.Slug = &slug\n\n\tif d.HasChange(\"description\") {\n\t\t// description omits empty values so set to ' '\n\t\tif description := d.Get(\"description\"); description.(string) == \"\" {\n\t\t\tdata.Description = \" \"\n\t\t} else {\n\t\t\tdata.Description = description.(string)\n\t\t}\n\t}\n\n\tdata.Tags = []*models.NestedTag{}\n\n\tparams := vpn.NewVpnTunnelGroupsUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Vpn.VpnTunnelGroupsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxVpnTunnelGroupRead(d, m)\n}\n\nfunc resourceNetboxVpnTunnelGroupDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := vpn.NewVpnTunnelGroupsDeleteParams().WithID(id)\n\n\t_, err := api.Vpn.VpnTunnelGroupsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*vpn.VpnTunnelGroupsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vpn_tunnel_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/vpn\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxVpnTunnelGroup_basic(t *testing.T) {\n\ttestSlug := \"vpntnlgrp_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_vpn_tunnel_group\" \"test\" {\n  name = \"%[1]s\"\n  slug = \"%[1]s\"\n  description = \"%[1]s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel_group.test\", \"slug\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel_group.test\", \"description\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vpn_tunnel_group.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_vpn_tunnel_group\", &resource.Sweeper{\n\t\tName:         \"netbox_vpn_tunnel_group\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := vpn.NewVpnTunnelGroupsListParams()\n\t\t\tres, err := api.Vpn.VpnTunnelGroupsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, clusterGroup := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*clusterGroup.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := vpn.NewVpnTunnelGroupsDeleteParams().WithID(clusterGroup.ID)\n\t\t\t\t\t_, err := api.Vpn.VpnTunnelGroupsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a vpn_tunnel_group\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vpn_tunnel_termination.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/vpn\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nvar resourceNetboxVpnTunnelTerminationRoleOptions = []string{\"peer\", \"hub\", \"spoke\"}\n\nfunc resourceNetboxVpnTunnelTermination() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxVpnTunnelTerminationCreate,\n\t\tRead:   resourceNetboxVpnTunnelTerminationRead,\n\t\tUpdate: resourceNetboxVpnTunnelTerminationUpdate,\n\t\tDelete: resourceNetboxVpnTunnelTerminationDelete,\n\n\t\tDescription: `:meta:subcategory:VPN Tunnels:From the [official documentation](https://docs.netbox.dev/en/stable/features/vpn-tunnels/):\n\n> NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces. For convenient organization, tunnels may be assigned to user-defined groups.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"tunnel_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"role\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tRequired:    true,\n\t\t\t\tDescription: buildValidValueDescription(resourceNetboxVpnTunnelTerminationRoleOptions),\n\t\t\t},\n\t\t\t\"virtual_machine_interface_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"virtual_machine_interface_id\", \"device_interface_id\"},\n\t\t\t},\n\t\t\t\"device_interface_id\": {\n\t\t\t\tType:         schema.TypeInt,\n\t\t\t\tOptional:     true,\n\t\t\t\tExactlyOneOf: []string{\"virtual_machine_interface_id\", \"device_interface_id\"},\n\t\t\t},\n\t\t\t\"outside_ip_address_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVpnTunnelTerminationCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := models.WritableTunnelTermination{}\n\n\ttunnelID := int64(d.Get(\"tunnel_id\").(int))\n\n\tdata.Tunnel = &tunnelID\n\tdata.Role = d.Get(\"role\").(string)\n\n\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\n\tswitch {\n\tcase vmInterfaceID != nil:\n\t\tdata.TerminationType = strToPtr(\"virtualization.vminterface\")\n\t\tdata.TerminationID = *vmInterfaceID\n\tcase deviceInterfaceID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.interface\")\n\t\tdata.TerminationID = *deviceInterfaceID\n\t}\n\n\tdata.OutsideIP = getOptionalInt(d, \"outside_ip_address_id\")\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tparams := vpn.NewVpnTunnelTerminationsCreateParams().WithData(&data)\n\n\tres, err := api.Vpn.VpnTunnelTerminationsCreate(params, nil)\n\tif err != nil {\n\t\t//return errors.New(getTextFromError(err))\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVpnTunnelTerminationRead(d, m)\n}\n\nfunc resourceNetboxVpnTunnelTerminationRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := vpn.NewVpnTunnelTerminationsReadParams().WithID(id)\n\n\tres, err := api.Vpn.VpnTunnelTerminationsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*vpn.VpnTunnelTerminationsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\ttunnelTermination := res.GetPayload()\n\td.Set(\"tunnel_id\", tunnelTermination.Tunnel.ID)\n\td.Set(\"role\", tunnelTermination.Role.Value)\n\n\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\n\tswitch {\n\tcase vmInterfaceID != nil:\n\t\td.Set(\"virtual_machine_interface_id\", tunnelTermination.TerminationID)\n\tcase deviceInterfaceID != nil:\n\t\td.Set(\"device_interface_id\", tunnelTermination.TerminationID)\n\t}\n\n\tif tunnelTermination.OutsideIP != nil {\n\t\td.Set(\"outside_ip_address_id\", tunnelTermination.OutsideIP.ID)\n\t}\n\n\tapi.readTags(d, res.GetPayload().Tags)\n\treturn nil\n}\n\nfunc resourceNetboxVpnTunnelTerminationUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableTunnelTermination{}\n\n\ttunnelID := int64(d.Get(\"tunnel_id\").(int))\n\tdata.Tunnel = &tunnelID\n\tdata.Role = d.Get(\"role\").(string)\n\n\tvmInterfaceID := getOptionalInt(d, \"virtual_machine_interface_id\")\n\tdeviceInterfaceID := getOptionalInt(d, \"device_interface_id\")\n\n\tswitch {\n\tcase vmInterfaceID != nil:\n\t\tdata.TerminationType = strToPtr(\"virtualization.vminterface\")\n\t\tdata.TerminationID = *vmInterfaceID\n\tcase deviceInterfaceID != nil:\n\t\tdata.TerminationType = strToPtr(\"dcim.interface\")\n\t\tdata.TerminationID = *deviceInterfaceID\n\t}\n\n\tdata.OutsideIP = getOptionalInt(d, \"outside_ip_address_id\")\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tdata.Tags = tags\n\n\tparams := vpn.NewVpnTunnelTerminationsUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Vpn.VpnTunnelTerminationsUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxVpnTunnelTerminationRead(d, m)\n}\n\nfunc resourceNetboxVpnTunnelTerminationDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := vpn.NewVpnTunnelTerminationsDeleteParams().WithID(id)\n\n\t_, err := api.Vpn.VpnTunnelTerminationsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*vpn.VpnTunnelTerminationsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vpn_tunnel_termination_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/vpn\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxVpnTunnelTerminationFullDependencies(testName string) string {\n\treturn fmt.Sprintf(`\n\tresource \"netbox_site\" \"test\" {\n\t\tname = \"%[1]s\"\n\t}\n\tresource \"netbox_device_role\" \"test\" {\n\t\tname = \"%[1]s\"\n\t\tcolor_hex = \"ff00ff\"\n\t}\n\tresource \"netbox_manufacturer\" \"test\" {\n\t\tname = \"%[1]s\"\n\t}\n\tresource \"netbox_device_type\" \"test\" {\n\t\tmodel = \"%[1]s\"\n\t\tmanufacturer_id = netbox_manufacturer.test.id\n\t}\n\tresource \"netbox_device\" \"test\" {\n\t\tname = \"%[1]s\"\n\t\tdevice_type_id = netbox_device_type.test.id\n\t\trole_id = netbox_device_role.test.id\n\t\tsite_id = netbox_site.test.id\n\t}\n\tresource \"netbox_device_interface\" \"test\" {\n\t\tname = \"eth0\"\n\t\tdevice_id = netbox_device.test.id\n\t\ttype = \"virtual\"\n\t}\n\tresource \"netbox_ip_address\" \"device_1\" {\n\t\tip_address = \"2.2.2.0/32\"\n\t\tstatus = \"active\"\n\t\tdevice_interface_id = netbox_device_interface.test.id\n\t}\n\tresource \"netbox_ip_address\" \"device_2\" {\n\t\tip_address = \"2.2.2.1/32\"\n\t\tstatus = \"active\"\n\t\tdevice_interface_id = netbox_device_interface.test.id\n\t}\n\n\tresource \"netbox_virtual_machine\" \"test\" {\n\t\tname = \"%[1]s\"\n\t\tsite_id = netbox_site.test.id\n\t}\n\tresource \"netbox_interface\" \"test\" {\n\t\tname = \"eth0\"\n\t\tvirtual_machine_id = netbox_virtual_machine.test.id\n\t}\n\tresource \"netbox_ip_address\" \"vm_1\" {\n\t\tip_address = \"2.2.2.2/32\"\n\t\tstatus = \"active\"\n\t\tvirtual_machine_interface_id = netbox_interface.test.id\n\t}\n\tresource \"netbox_ip_address\" \"vm_2\" {\n\t\tip_address = \"2.2.2.3/32\"\n\t\tstatus = \"active\"\n\t\tvirtual_machine_interface_id = netbox_interface.test.id\n\t}\n\n\tresource \"netbox_vpn_tunnel_group\" \"test\" {\n\t\tname = \"%[1]s\"\n\t\tdescription = \"%[1]s\"\n\t}\n\tresource \"netbox_tag\" \"test\" {\n\t\tname = \"%[1]s\"\n\t}\n\tresource \"netbox_vpn_tunnel\" \"test\" {\n\t\tname = \"%[1]s\"\n\t\tencapsulation = \"ipsec-transport\"\n\t\tstatus = \"active\"\n\t\ttunnel_group_id = netbox_vpn_tunnel_group.test.id\n\t}\n\t`, testName)\n}\n\nfunc TestAccNetboxVpnTunnelTermination_basic(t *testing.T) {\n\ttestSlug := \"vpnterm_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVpnTunnelTerminationFullDependencies(testName) + `\nresource \"netbox_vpn_tunnel_termination\" \"device\" {\n\trole = \"peer\"\n\ttunnel_id = netbox_vpn_tunnel.test.id\n\tdevice_interface_id = netbox_device_interface.test.id\n\n\ttags = [netbox_tag.test.name]\n}\nresource \"netbox_vpn_tunnel_termination\" \"vm\" {\n\trole = \"peer\"\n\ttunnel_id = netbox_vpn_tunnel.test.id\n\tvirtual_machine_interface_id = netbox_interface.test.id\n\n\toutside_ip_address_id = netbox_ip_address.vm_1.id\n}`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vpn_tunnel_termination.device\", \"tunnel_id\", \"netbox_vpn_tunnel.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vpn_tunnel_termination.vm\", \"tunnel_id\", \"netbox_vpn_tunnel.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vpn_tunnel_termination.vm\", \"outside_ip_address_id\", \"netbox_ip_address.vm_1\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel_termination.device\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel_termination.device\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVpnTunnelTerminationFullDependencies(testName) + `\nresource \"netbox_ip_address\" \"outside_ip\" {\n\tip_address = \"203.0.113.2/24\"\n\tstatus = \"active\"\n}\n\nresource \"netbox_vpn_tunnel_termination\" \"device\" {\n\trole = \"peer\"\n\ttunnel_id = netbox_vpn_tunnel.test.id\n\tdevice_interface_id = netbox_device_interface.test.id\n\toutside_ip_address_id = netbox_ip_address.outside_ip.id\n\n\ttags = [netbox_tag.test.name]\n}\nresource \"netbox_vpn_tunnel_termination\" \"vm\" {\n\trole = \"peer\"\n\ttunnel_id = netbox_vpn_tunnel.test.id\n\tvirtual_machine_interface_id = netbox_interface.test.id\n\n\toutside_ip_address_id = netbox_ip_address.vm_1.id\n}`,\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vpn_tunnel_termination.device\", \"tunnel_id\", \"netbox_vpn_tunnel.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vpn_tunnel_termination.device\", \"outside_ip_address_id\", \"netbox_ip_address.outside_ip\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vpn_tunnel.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_vpn_tunnel_termination\", &resource.Sweeper{\n\t\tName:         \"netbox_vpn_tunnel_termination\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := vpn.NewVpnTunnelTerminationsListParams()\n\t\t\tres, err := api.Vpn.VpnTunnelTerminationsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, vpnTunnelTermination := range res.GetPayload().Results {\n\t\t\t\tdeleteParams := vpn.NewVpnTunnelTerminationsDeleteParams().WithID(vpnTunnelTermination.ID)\n\t\t\t\t_, err := api.Vpn.VpnTunnelTerminationsDelete(deleteParams, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tlog.Print(\"[DEBUG] Deleted a vpn tunnel termination\")\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vpn_tunnel_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/vpn\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxVpnTunnel_basic(t *testing.T) {\n\ttestSlug := \"vpntun_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_vpn_tunnel_group\" \"test\" {\n  name = \"%[1]s\"\n  description = \"%[1]s\"\n}\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\nresource \"netbox_vpn_tunnel\" \"test\" {\n  name = \"%[1]s\"\n  encapsulation = \"ipsec-transport\"\n  status = \"active\"\n  tunnel_group_id = netbox_vpn_tunnel_group.test.id\n\n  description = \"%[1]s\"\n  tenant_id = netbox_tenant.test.id\n  tunnel_id = 123\n  tags = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel.test\", \"encapsulation\", \"ipsec-transport\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel.test\", \"description\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel.test\", \"tunnel_id\", \"123\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vpn_tunnel.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vpn_tunnel.test\", \"tunnel_group_id\", \"netbox_vpn_tunnel_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vpn_tunnel.test\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vpn_tunnel.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_vpn_tunnel\", &resource.Sweeper{\n\t\tName:         \"netbox_vpn_tunnel\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := vpn.NewVpnTunnelsListParams()\n\t\t\tres, err := api.Vpn.VpnTunnelsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, vpnTunnel := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*vpnTunnel.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := vpn.NewVpnTunnelsDeleteParams().WithID(vpnTunnel.ID)\n\t\t\t\t\t_, err := api.Vpn.VpnTunnelsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a vpnTunnel\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vrf.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxVrf() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxVrfCreate,\n\t\tRead:   resourceNetboxVrfRead,\n\t\tUpdate: resourceNetboxVrfUpdate,\n\t\tDelete: resourceNetboxVrfDelete,\n\n\t\tDescription: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#virtual-routing-and-forwarding-vrf):\n\n> A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space). Each VRF may be assigned to a specific tenant to aid in organizing the available IP space by customer or internal user.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"enforce_unique\": {\n\t\t\t\tType:     schema.TypeBool,\n\t\t\t\tOptional: true,\n\t\t\t\tDefault:  true,\n\t\t\t},\n\t\t\t\"rd\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 21),\n\t\t\t},\n\n\t\t\ttagsKey: tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxVrfCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tdata := models.WritableVRF{}\n\n\tname := d.Get(\"name\").(string)\n\ttenantID := int64(d.Get(\"tenant_id\").(int))\n\tenforceUnique := d.Get(\"enforce_unique\").(bool)\n\trd := d.Get(\"rd\").(string)\n\n\tdata.Name = &name\n\tif tenantID != 0 {\n\t\tdata.Tenant = &tenantID\n\t}\n\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.EnforceUnique = enforceUnique\n\tif rd != \"\" {\n\t\tdata.Rd = &rd\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdata.ExportTargets = []int64{}\n\tdata.ImportTargets = []int64{}\n\n\tparams := ipam.NewIpamVrfsCreateParams().WithData(&data)\n\n\tres, err := api.Ipam.IpamVrfsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxVrfRead(d, m)\n}\n\nfunc resourceNetboxVrfRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamVrfsReadParams().WithID(id)\n\n\tres, err := api.Ipam.IpamVrfsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamVrfsReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\t// If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\tvrf := res.GetPayload()\n\td.Set(\"name\", vrf.Name)\n\td.Set(\"description\", vrf.Description)\n\td.Set(\"enforce_unique\", vrf.EnforceUnique)\n\tif vrf.Rd != nil {\n\t\td.Set(\"rd\", *vrf.Rd)\n\t} else {\n\t\td.Set(\"rd\", nil)\n\t}\n\tif vrf.Tenant != nil {\n\t\td.Set(\"tenant_id\", vrf.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\treturn nil\n}\n\nfunc resourceNetboxVrfUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.WritableVRF{}\n\n\tname := d.Get(\"name\").(string)\n\tenforceUnique := d.Get(\"enforce_unique\").(bool)\n\n\ttags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\n\tdata.Name = &name\n\tdata.Tags = tags\n\tdata.ExportTargets = []int64{}\n\tdata.ImportTargets = []int64{}\n\tdata.Description = getOptionalStr(d, \"description\", true)\n\tdata.EnforceUnique = enforceUnique\n\n\tif rd, ok := d.GetOk(\"rd\"); ok {\n\t\tdata.Rd = strToPtr(rd.(string))\n\t}\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\tparams := ipam.NewIpamVrfsPartialUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Ipam.IpamVrfsPartialUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxVrfRead(d, m)\n}\n\nfunc resourceNetboxVrfDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := ipam.NewIpamVrfsDeleteParams().WithID(id)\n\n\t_, err := api.Ipam.IpamVrfsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*ipam.IpamVrfsDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_vrf_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/ipam\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxVrfTagDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test_a\" {\n  name = \"%[1]sa\"\n}\n\nresource \"netbox_tag\" \"test_b\" {\n  name = \"%[1]sb\"\n}\n`, testName)\n}\n\nfunc testAccNetboxVrfTenantDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tenant\" \"test_tenant_a\" {\n  name = \"%[1]sa\"\n}\nresource \"netbox_tenant\" \"test_tenant_b\" {\n  name = \"%[1]sb\"\n}\n`, testName)\n}\n\nfunc TestAccNetboxVrf_basic(t *testing.T) {\n\ttestSlug := \"vrf_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_vrf\" \"test\" {\n  name        = \"%s\"\n  description = \"my-description\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test\", \"description\", \"my-description\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vrf.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVrf_tags(t *testing.T) {\n\ttestSlug := \"vrf_tag\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVrfTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vrf\" \"test_tags\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tags\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tags\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tags\", \"tags.0\", testName+\"a\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVrfTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vrf\" \"test_tags\" {\n  name = \"%[1]s\"\n  tags = [netbox_tag.test_a.name, netbox_tag.test_b.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tags\", \"tags.#\", \"2\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tags\", \"tags.0\", testName+\"a\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tags\", \"tags.1\", testName+\"b\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVrfTagDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vrf\" \"test_tags\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tags\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVrf_tenant(t *testing.T) {\n\ttestSlug := \"vrf_tenant\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVrfTenantDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vrf\" \"test_tenant\" {\n  name = \"%[1]s\"\n  tenant_id = netbox_tenant.test_tenant_a.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tenant\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vrf.test_tenant\", \"tenant_id\", \"netbox_tenant.test_tenant_a\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxVrfTenantDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_vrf\" \"test_tenant\" {\n  name = \"%[1]s\"\n  tenant_id = netbox_tenant.test_tenant_b.id\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_tenant\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_vrf.test_tenant\", \"tenant_id\", \"netbox_tenant.test_tenant_b\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVrf_rd(t *testing.T) {\n\ttestSlug := \"vrf_rd\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_vrf\" \"test_rd\" {\n\tname        = \"%s\"\n\trd          = \"123:456\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_rd\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_rd\", \"rd\", \"123:456\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_vrf.test_rd\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxVrf_enforceUnique(t *testing.T) {\n\ttestSlug := \"vrf_enforce_unique\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_vrf\" \"test_enforce_unique\" {\n\tname        = \"%s-true\"\n\tenforce_unique = true\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_enforce_unique\", \"name\", testName+\"-true\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_enforce_unique\", \"enforce_unique\", \"true\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_vrf\" \"test_enforce_unique_false\" {\n\tname        = \"%s-false\"\n\tenforce_unique = false\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_enforce_unique_false\", \"name\", testName+\"-false\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_vrf.test_enforce_unique_false\", \"enforce_unique\", \"false\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_vrf\", &resource.Sweeper{\n\t\tName:         \"netbox_vrf\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := ipam.NewIpamVrfsListParams()\n\t\t\tres, err := api.Ipam.IpamVrfsList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, vrf := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*vrf.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := ipam.NewIpamVrfsDeleteParams().WithID(vrf.ID)\n\t\t\t\t\t_, err := api.Ipam.IpamVrfsDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a vrf\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_webhook.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxWebhookHTTPMethodOptions = []string{\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"}\n\nfunc resourceNetboxWebhook() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxWebhookCreate,\n\t\tRead:   resourceNetboxWebhookRead,\n\t\tUpdate: resourceNetboxWebhookUpdate,\n\t\tDelete: resourceNetboxWebhookDelete,\n\n\t\tDescription: `:meta:subcategory:Extras:From the [official documentation](https://docs.netbox.dev/en/stable/integrations/webhooks/):\n\n> A webhook is a mechanism for conveying to some external system a change that took place in NetBox. For example, you may want to notify a monitoring system whenever the status of a device is updated in NetBox. This can be done by creating a webhook for the device model in NetBox and identifying the webhook receiver. When NetBox detects a change to a device, an HTTP request containing the details of the change and who made it be sent to the specified receiver.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"payload_url\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"body_template\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t\tDiffSuppressFunc: func(k, oldValue, newValue string, d *schema.ResourceData) bool {\n\t\t\t\t\tequal, _ := jsonSemanticCompare(oldValue, newValue)\n\t\t\t\t\treturn equal\n\t\t\t\t},\n\t\t\t\tDiffSuppressOnRefresh: true,\n\t\t\t},\n\t\t\t\"http_method\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxWebhookHTTPMethodOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxWebhookHTTPMethodOptions),\n\t\t\t\tDefault:      \"POST\",\n\t\t\t},\n\t\t\t\"http_content_type\": {\n\t\t\t\tType:        schema.TypeString,\n\t\t\t\tOptional:    true,\n\t\t\t\tDescription: \"The complete list of official content types is available [here](https://www.iana.org/assignments/media-types/media-types.xhtml).\",\n\t\t\t\tDefault:     \"application/json\",\n\t\t\t},\n\t\t\t\"additional_headers\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"ca_file_path\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxWebhookCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tdata := &models.Webhook{}\n\tname := d.Get(\"name\").(string)\n\tdata.Name = &name\n\tpayloadURL := d.Get(\"payload_url\").(string)\n\tdata.PayloadURL = &payloadURL\n\tbodyTemplate := d.Get(\"body_template\").(string)\n\tdata.BodyTemplate = bodyTemplate\n\tdata.HTTPMethod = getOptionalStr(d, \"http_method\", false)\n\tdata.HTTPContentType = getOptionalStr(d, \"http_content_type\", false)\n\tdata.AdditionalHeaders = getOptionalStr(d, \"additional_headers\", false)\n\tdata.CaFilePath = strToPtr(getOptionalStr(d, \"ca_file_path\", false))\n\n\tparams := extras.NewExtrasWebhooksCreateParams().WithData(data)\n\n\tres, err := api.Extras.ExtrasWebhooksCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxWebhookRead(d, m)\n}\n\nfunc resourceNetboxWebhookRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasWebhooksReadParams().WithID(id)\n\n\tres, err := api.Extras.ExtrasWebhooksRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasWebhooksReadDefault); ok {\n\t\t\terrorcode := errresp.Code()\n\t\t\tif errorcode == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\twebhook := res.GetPayload()\n\td.Set(\"name\", webhook.Name)\n\td.Set(\"payload_url\", webhook.PayloadURL)\n\td.Set(\"body_template\", webhook.BodyTemplate)\n\td.Set(\"http_method\", webhook.HTTPMethod)\n\td.Set(\"http_content_type\", webhook.HTTPContentType)\n\td.Set(\"additional_headers\", webhook.AdditionalHeaders)\n\td.Set(\"ca_file_path\", webhook.CaFilePath)\n\n\treturn nil\n}\n\nfunc resourceNetboxWebhookUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tdata := models.Webhook{}\n\n\tname := d.Get(\"name\").(string)\n\tpayloadURL := d.Get(\"payload_url\").(string)\n\tbodyTemplate := d.Get(\"body_template\").(string)\n\n\tdata.Name = &name\n\tdata.PayloadURL = &payloadURL\n\tdata.BodyTemplate = bodyTemplate\n\tdata.HTTPMethod = getOptionalStr(d, \"http_method\", false)\n\tdata.HTTPContentType = getOptionalStr(d, \"http_content_type\", false)\n\tdata.AdditionalHeaders = getOptionalStr(d, \"additional_headers\", false)\n\tdata.CaFilePath = strToPtr(getOptionalStr(d, \"ca_file_path\", false))\n\n\tparams := extras.NewExtrasWebhooksUpdateParams().WithID(id).WithData(&data)\n\n\t_, err := api.Extras.ExtrasWebhooksUpdate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxWebhookRead(d, m)\n}\n\nfunc resourceNetboxWebhookDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\tparams := extras.NewExtrasWebhooksDeleteParams().WithID(id)\n\n\t_, err := api.Extras.ExtrasWebhooksDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*extras.ExtrasWebhooksDeleteDefault); ok {\n\t\t\tif errresp.Code() == 404 {\n\t\t\t\td.SetId(\"\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_webhook_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/terraform\"\n)\n\nfunc TestAccNetboxWebhook_basic(t *testing.T) {\n\ttestName := testAccGetTestName(\"webhook_basic\")\n\ttestPayloadURL := \"https://example.com/webhook\"\n\ttestBodyTemplate := \"Sample Body\"\n\ttestAdditionalHeaders := \"Authentication: Bearer abcdef123456\"\n\ttestCaFilePath := \"/etc/ssl/certs\"\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders:    testAccProviders,\n\t\tCheckDestroy: testAccCheckNetBoxWebhookDestroy,\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_webhook\" \"test\" {\n  name               = \"%s\"\n  payload_url        = \"%s\"\n  body_template      = \"%s\"\n  additional_headers = \"%s\"\n  ca_file_path = \"%s\"\n}`, testName, testPayloadURL, testBodyTemplate, testAdditionalHeaders, testCaFilePath),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"payload_url\", testPayloadURL),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"body_template\", testBodyTemplate),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"additional_headers\", testAdditionalHeaders),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"ca_file_path\", testCaFilePath),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_webhook.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxWebhook_update(t *testing.T) {\n\ttestName := testAccGetTestName(\"webhook_update\")\n\ttestPayloadURL := \"https://example.com/webhookupdate\"\n\ttestBodyTemplate := `{\"text\": \"This is a sample json\"}`\n\ttestHTTPMethod := \"PUT\"\n\ttestHTTPContentType := \"application/xml\"\n\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_webhook\" \"test\" {\n\tname              = \"%s\"\n\tpayload_url       = \"%s\"\n\tbody_template        = <<-EOT\n\t{\"text\": \"This is a sample json\"}\n\tEOT\n        http_method       = \"%s\"\n        http_content_type = \"%s\"\n  }`, testName, testPayloadURL, testHTTPMethod, testHTTPContentType),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"payload_url\", testPayloadURL),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"body_template\", testBodyTemplate),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"http_method\", testHTTPMethod),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"http_content_type\", testHTTPContentType),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_webhook\" \"test\" {\n  name                 = \"%s_updated\"\n  payload_url          = \"%s\"\n  body_template        = <<-EOT\n  {\"text\": \"This is a sample json\"}\n  EOT\n}`, testName, testPayloadURL),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"name\", testName+\"_updated\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"payload_url\", testPayloadURL),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"body_template\", testBodyTemplate),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxWebhook_import(t *testing.T) {\n\ttestName := testAccGetTestName(\"webhook_import\")\n\ttestPayloadURL := \"https://test2.com/webhook\"\n\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_webhook\" \"test\" {\n  name                   = \"%s\"\n  payload_url            = \"%s\"\n}`, testName, testPayloadURL),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_webhook.test\", \"payload_url\", testPayloadURL),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_webhook.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc testAccCheckNetBoxWebhookDestroy(s *terraform.State) error {\n\tclient := testAccProvider.Meta().(*providerState)\n\n\tfor _, rs := range s.RootModule().Resources {\n\t\tif rs.Type != \"netbox_webhook\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Fetch the webhook by ID\n\t\t// Retrieve our interface by referencing it's state ID for API lookup\n\t\tstateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)\n\t\twebhook, err := client.Extras.ExtrasWebhooksRead(extras.NewExtrasWebhooksReadParams().WithID(stateID), nil)\n\t\tif err == nil && webhook != nil {\n\t\t\treturn fmt.Errorf(\"Webhook %s still exists\", rs.Primary.ID)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tresource.AddTestSweepers(\"netbox_webhook\", &resource.Sweeper{\n\t\tName:         \"netbox_webhook\",\n\t\tDependencies: []string{},\n\t\tF: func(region string) error {\n\t\t\tm, err := sharedClientForRegion(region)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Error getting client: %s\", err)\n\t\t\t}\n\t\t\tapi := m.(*providerState)\n\t\t\tparams := extras.NewExtrasWebhooksListParams()\n\t\t\tres, err := api.Extras.ExtrasWebhooksList(params, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, webhook := range res.GetPayload().Results {\n\t\t\t\tif strings.HasPrefix(*webhook.Name, testPrefix) {\n\t\t\t\t\tdeleteParams := extras.NewExtrasWebhooksDeleteParams().WithID(webhook.ID)\n\t\t\t\t\t_, err := api.Extras.ExtrasWebhooksDelete(deleteParams, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tlog.Print(\"[DEBUG] Deleted a webhook\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_wireless_helpers.go",
    "content": "package netbox\n\nimport (\n\t\"github.com/fbreckle/go-netbox/netbox/client/wireless\"\n\t\"github.com/go-openapi/runtime\"\n\t\"github.com/go-openapi/strfmt\"\n\t\"github.com/go-viper/mapstructure/v2\"\n)\n\ntype wirelessInterceptWriter struct {\n\truntime.ClientRequest\n\tfields map[string]any\n}\n\nfunc (iw wirelessInterceptWriter) SetBodyParam(p any) error {\n\tout := make(map[string]any)\n\tdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{\n\t\tTagName: \"json\",\n\t\tResult:  &out,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := dec.Decode(p); err != nil {\n\t\treturn err\n\t}\n\tfor fieldName, value := range iw.fields {\n\t\tout[fieldName] = value\n\t}\n\treturn iw.ClientRequest.SetBodyParam(out)\n}\n\ntype wirelessInterceptParams struct {\n\tinner  runtime.ClientRequestWriter\n\tfields map[string]any\n}\n\nfunc (ip wirelessInterceptParams) WriteToRequest(req runtime.ClientRequest, reg strfmt.Registry) error {\n\twriter := wirelessInterceptWriter{ClientRequest: req, fields: ip.fields}\n\treturn ip.inner.WriteToRequest(writer, reg)\n}\n\nfunc hackSerializeWirelessWithValues(fields map[string]any) wireless.ClientOption {\n\toverrideFields := make(map[string]any, len(fields))\n\tfor fieldName, value := range fields {\n\t\toverrideFields[fieldName] = value\n\t}\n\treturn func(co *runtime.ClientOperation) {\n\t\toriginalParams := co.Params\n\t\tco.Params = wirelessInterceptParams{inner: originalParams, fields: overrideFields}\n\t}\n}\n\nfunc hackSerializeWirelessAsNull(fields ...string) wireless.ClientOption {\n\toverrideFields := make(map[string]any, len(fields))\n\tfor _, field := range fields {\n\t\toverrideFields[field] = nil\n\t}\n\treturn hackSerializeWirelessWithValues(overrideFields)\n}\n"
  },
  {
    "path": "netbox/resource_netbox_wireless_lan.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/wireless\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nvar resourceNetboxWirelessLANStatusOptions = []string{\"active\", \"reserved\", \"disabled\", \"deprecated\"}\nvar resourceNetboxWirelessLANAuthTypeOptions = []string{\"open\", \"wep\", \"wpa-personal\", \"wpa-enterprise\"}\nvar resourceNetboxWirelessLANAuthCipherOptions = []string{\"auto\", \"tkip\", \"aes\"}\n\nfunc resourceNetboxWirelessLAN() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxWirelessLANCreate,\n\t\tRead:   resourceNetboxWirelessLANRead,\n\t\tUpdate: resourceNetboxWirelessLANUpdate,\n\t\tDelete: resourceNetboxWirelessLANDelete,\n\n\t\tDescription: `:meta:subcategory:Wireless:\n\n> A Wireless LAN represents a broadcast wireless network, identified by its SSID and optional authentication settings.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"ssid\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tRequired:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 32),\n\t\t\t},\n\t\t\t\"status\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tDefault:      \"active\",\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxWirelessLANStatusOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxWirelessLANStatusOptions),\n\t\t\t},\n\t\t\t\"group_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"tenant_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"vlan_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"auth_type\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxWirelessLANAuthTypeOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxWirelessLANAuthTypeOptions),\n\t\t\t},\n\t\t\t\"auth_cipher\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tValidateFunc: validation.StringInSlice(resourceNetboxWirelessLANAuthCipherOptions, false),\n\t\t\t\tDescription:  buildValidValueDescription(resourceNetboxWirelessLANAuthCipherOptions),\n\t\t\t},\n\t\t\t\"auth_psk\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tSensitive:    true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(0, 64),\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"comments\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t\ttagsKey:         tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxWirelessLANCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tssid := d.Get(\"ssid\").(string)\n\tstatus := d.Get(\"status\").(string)\n\n\tdata := &models.WritableWirelessLAN{\n\t\tSsid:        &ssid,\n\t\tStatus:      status,\n\t\tAuthType:    d.Get(\"auth_type\").(string),\n\t\tAuthCipher:  d.Get(\"auth_cipher\").(string),\n\t\tAuthPsk:     d.Get(\"auth_psk\").(string),\n\t\tDescription: d.Get(\"description\").(string),\n\t\tComments:    d.Get(\"comments\").(string),\n\t}\n\n\tif groupID, ok := d.GetOk(\"group_id\"); ok {\n\t\tdata.Group = int64ToPtr(int64(groupID.(int)))\n\t}\n\n\tif tenantID, ok := d.GetOk(\"tenant_id\"); ok {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID.(int)))\n\t}\n\n\tif vlanID, ok := d.GetOk(\"vlan_id\"); ok {\n\t\tdata.Vlan = int64ToPtr(int64(vlanID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := wireless.NewWirelessWirelessLansCreateParams().WithData(data)\n\tres, err := api.Wireless.WirelessWirelessLansCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxWirelessLANRead(d, m)\n}\n\nfunc resourceNetboxWirelessLANRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := wireless.NewWirelessWirelessLansReadParams().WithID(id)\n\tres, err := api.Wireless.WirelessWirelessLansRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*wireless.WirelessWirelessLansReadDefault); ok && errresp.Code() == 404 {\n\t\t\td.SetId(\"\")\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\twlan := res.GetPayload()\n\td.Set(\"ssid\", wlan.Ssid)\n\td.Set(\"description\", wlan.Description)\n\td.Set(\"comments\", wlan.Comments)\n\td.Set(\"auth_psk\", wlan.AuthPsk)\n\n\tif wlan.Status != nil {\n\t\td.Set(\"status\", wlan.Status.Value)\n\t} else {\n\t\td.Set(\"status\", nil)\n\t}\n\n\tif wlan.AuthType != nil {\n\t\td.Set(\"auth_type\", wlan.AuthType.Value)\n\t} else {\n\t\td.Set(\"auth_type\", nil)\n\t}\n\n\tif wlan.AuthCipher != nil {\n\t\td.Set(\"auth_cipher\", wlan.AuthCipher.Value)\n\t} else {\n\t\td.Set(\"auth_cipher\", nil)\n\t}\n\n\tif wlan.Group != nil {\n\t\td.Set(\"group_id\", wlan.Group.ID)\n\t} else {\n\t\td.Set(\"group_id\", nil)\n\t}\n\n\tif wlan.Tenant != nil {\n\t\td.Set(\"tenant_id\", wlan.Tenant.ID)\n\t} else {\n\t\td.Set(\"tenant_id\", nil)\n\t}\n\n\tif wlan.Vlan != nil {\n\t\td.Set(\"vlan_id\", wlan.Vlan.ID)\n\t} else {\n\t\td.Set(\"vlan_id\", nil)\n\t}\n\n\tcf := getCustomFields(wlan.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, wlan.Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxWirelessLANUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tssid := d.Get(\"ssid\").(string)\n\tdata := models.WritableWirelessLAN{\n\t\tSsid:        &ssid,\n\t\tStatus:      d.Get(\"status\").(string),\n\t\tDescription: getOptionalStr(d, \"description\", true),\n\t\tComments:    getOptionalStr(d, \"comments\", true),\n\t}\n\n\toverrideFields := make(map[string]any)\n\n\tgroupID := d.Get(\"group_id\").(int)\n\tif groupID != 0 {\n\t\tdata.Group = int64ToPtr(int64(groupID))\n\t} else {\n\t\toverrideFields[\"group\"] = nil\n\t}\n\n\ttenantID := d.Get(\"tenant_id\").(int)\n\tif tenantID != 0 {\n\t\tdata.Tenant = int64ToPtr(int64(tenantID))\n\t} else {\n\t\toverrideFields[\"tenant\"] = nil\n\t}\n\n\tvlanID := d.Get(\"vlan_id\").(int)\n\tif vlanID != 0 {\n\t\tdata.Vlan = int64ToPtr(int64(vlanID))\n\t} else {\n\t\toverrideFields[\"vlan\"] = nil\n\t}\n\n\tif authType, ok := d.GetOk(\"auth_type\"); ok {\n\t\tdata.AuthType = authType.(string)\n\t} else {\n\t\toverrideFields[\"auth_type\"] = nil\n\t}\n\n\tif authCipher, ok := d.GetOk(\"auth_cipher\"); ok {\n\t\tdata.AuthCipher = authCipher.(string)\n\t} else {\n\t\toverrideFields[\"auth_cipher\"] = nil\n\t}\n\n\tif authPSK, ok := d.GetOk(\"auth_psk\"); ok {\n\t\tdata.AuthPsk = authPSK.(string)\n\t} else {\n\t\toverrideFields[\"auth_psk\"] = \"\"\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := wireless.NewWirelessWirelessLansPartialUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Wireless.WirelessWirelessLansPartialUpdate(params, nil, hackSerializeWirelessWithValues(overrideFields))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxWirelessLANRead(d, m)\n}\n\nfunc resourceNetboxWirelessLANDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := wireless.NewWirelessWirelessLansDeleteParams().WithID(id)\n\t_, err := api.Wireless.WirelessWirelessLansDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*wireless.WirelessWirelessLansDeleteDefault); ok && errresp.Code() == 404 {\n\t\t\td.SetId(\"\")\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_wireless_lan_group.go",
    "content": "package netbox\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client/wireless\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n)\n\nfunc resourceNetboxWirelessLANGroup() *schema.Resource {\n\treturn &schema.Resource{\n\t\tCreate: resourceNetboxWirelessLANGroupCreate,\n\t\tRead:   resourceNetboxWirelessLANGroupRead,\n\t\tUpdate: resourceNetboxWirelessLANGroupUpdate,\n\t\tDelete: resourceNetboxWirelessLANGroupDelete,\n\n\t\tDescription: `:meta:subcategory:Wireless:\n\n> A Wireless LAN Group is used to organize wireless LANs into a recursive hierarchy.`,\n\n\t\tSchema: map[string]*schema.Schema{\n\t\t\t\"name\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tRequired: true,\n\t\t\t},\n\t\t\t\"slug\": {\n\t\t\t\tType:         schema.TypeString,\n\t\t\t\tOptional:     true,\n\t\t\t\tComputed:     true,\n\t\t\t\tValidateFunc: validation.StringLenBetween(1, 100),\n\t\t\t},\n\t\t\t\"parent_id\": {\n\t\t\t\tType:     schema.TypeInt,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\tType:     schema.TypeString,\n\t\t\t\tOptional: true,\n\t\t\t},\n\t\t\tcustomFieldsKey: customFieldsSchema,\n\t\t\ttagsKey:         tagsSchema,\n\t\t},\n\t\tImporter: &schema.ResourceImporter{\n\t\t\tStateContext: schema.ImportStatePassthroughContext,\n\t\t},\n\t}\n}\n\nfunc resourceNetboxWirelessLANGroupCreate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\n\tname := d.Get(\"name\").(string)\n\tdescription := d.Get(\"description\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tslug := getSlug(name)\n\tif slugOk {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata := &models.WritableWirelessLANGroup{\n\t\tName:        &name,\n\t\tSlug:        &slug,\n\t\tDescription: description,\n\t}\n\n\tif parentID, ok := d.GetOk(\"parent_id\"); ok {\n\t\tdata.Parent = int64ToPtr(int64(parentID.(int)))\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := wireless.NewWirelessWirelessLanGroupsCreateParams().WithData(data)\n\tres, err := api.Wireless.WirelessWirelessLanGroupsCreate(params, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.SetId(strconv.FormatInt(res.GetPayload().ID, 10))\n\n\treturn resourceNetboxWirelessLANGroupRead(d, m)\n}\n\nfunc resourceNetboxWirelessLANGroupRead(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := wireless.NewWirelessWirelessLanGroupsReadParams().WithID(id)\n\tres, err := api.Wireless.WirelessWirelessLanGroupsRead(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*wireless.WirelessWirelessLanGroupsReadDefault); ok && errresp.Code() == 404 {\n\t\t\td.SetId(\"\")\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\tgroup := res.GetPayload()\n\td.Set(\"name\", group.Name)\n\td.Set(\"slug\", group.Slug)\n\td.Set(\"description\", group.Description)\n\n\tif group.Parent != nil {\n\t\td.Set(\"parent_id\", group.Parent.ID)\n\t} else {\n\t\td.Set(\"parent_id\", nil)\n\t}\n\n\tcf := getCustomFields(group.CustomFields)\n\tif cf != nil {\n\t\td.Set(customFieldsKey, cf)\n\t}\n\tapi.readTags(d, group.Tags)\n\n\treturn nil\n}\n\nfunc resourceNetboxWirelessLANGroupUpdate(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tname := d.Get(\"name\").(string)\n\n\tslugValue, slugOk := d.GetOk(\"slug\")\n\tslug := getSlug(name)\n\tif slugOk {\n\t\tslug = slugValue.(string)\n\t}\n\n\tdata := models.WritableWirelessLANGroup{\n\t\tName:        &name,\n\t\tSlug:        &slug,\n\t\tDescription: getOptionalStr(d, \"description\", true),\n\t}\n\n\tvar nullFields []string\n\n\tparentID := d.Get(\"parent_id\").(int)\n\tif parentID != 0 {\n\t\tdata.Parent = int64ToPtr(int64(parentID))\n\t} else {\n\t\tnullFields = append(nullFields, \"parent\")\n\t}\n\n\tvar err error\n\tdata.Tags, err = getNestedTagListFromResourceDataSet(api, d.Get(tagsAllKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cf, ok := d.GetOk(customFieldsKey); ok {\n\t\tdata.CustomFields = cf\n\t}\n\n\tparams := wireless.NewWirelessWirelessLanGroupsPartialUpdateParams().WithID(id).WithData(&data)\n\t_, err = api.Wireless.WirelessWirelessLanGroupsPartialUpdate(params, nil, hackSerializeWirelessAsNull(nullFields...))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn resourceNetboxWirelessLANGroupRead(d, m)\n}\n\nfunc resourceNetboxWirelessLANGroupDelete(d *schema.ResourceData, m interface{}) error {\n\tapi := m.(*providerState)\n\tid, _ := strconv.ParseInt(d.Id(), 10, 64)\n\n\tparams := wireless.NewWirelessWirelessLanGroupsDeleteParams().WithID(id)\n\t_, err := api.Wireless.WirelessWirelessLanGroupsDelete(params, nil)\n\tif err != nil {\n\t\tif errresp, ok := err.(*wireless.WirelessWirelessLanGroupsDeleteDefault); ok && errresp.Code() == 404 {\n\t\t\td.SetId(\"\")\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "netbox/resource_netbox_wireless_lan_group_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc TestAccNetboxWirelessLANGroup_basic(t *testing.T) {\n\ttestSlug := \"wlangrp_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\trandomSlug := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_wireless_lan_group\" \"parent\" {\n  name        = \"%[1]s\"\n  slug        = \"%[2]s\"\n  description = \"foo bar\"\n  tags        = [netbox_tag.test.name]\n}\n\nresource \"netbox_wireless_lan_group\" \"child\" {\n  name      = \"%[1]s-child\"\n  slug      = \"%[2]s-c\"\n  parent_id = netbox_wireless_lan_group.parent.id\n}`, testName, randomSlug),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.parent\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.parent\", \"slug\", randomSlug),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.parent\", \"description\", \"foo bar\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.parent\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.parent\", \"tags.0\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.child\", \"name\", fmt.Sprintf(\"%s-child\", testName)),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.child\", \"slug\", fmt.Sprintf(\"%s-c\", randomSlug)),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_wireless_lan_group.child\", \"parent_id\", \"netbox_wireless_lan_group.parent\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_wireless_lan_group.parent\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxWirelessLANGroup_defaultSlug(t *testing.T) {\n\ttestSlug := \"wlangrp_defslug\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_wireless_lan_group\" \"test\" {\n  name = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.test\", \"slug\", getSlug(testName)),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxWirelessLANGroup_updateParentAndDescription(t *testing.T) {\n\ttestSlug := \"wlangrp_update\"\n\ttestName := testAccGetTestName(testSlug)\n\tparentName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_wireless_lan_group\" \"parent\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_wireless_lan_group\" \"test\" {\n  name        = \"%[2]s\"\n  description = \"foo bar\"\n  parent_id   = netbox_wireless_lan_group.parent.id\n}`, parentName, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.test\", \"description\", \"foo bar\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_wireless_lan_group.test\", \"parent_id\", \"netbox_wireless_lan_group.parent\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_wireless_lan_group\" \"parent\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_wireless_lan_group\" \"test\" {\n  name = \"%[2]s\"\n}`, parentName, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.test\", \"name\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan_group.test\", \"parent_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/resource_netbox_wireless_lan_test.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource\"\n)\n\nfunc testAccNetboxWirelessLANDependencies(testName string) string {\n\treturn fmt.Sprintf(`\nresource \"netbox_tag\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_tenant\" \"test\" {\n  name = \"%[1]s\"\n}\n\nresource \"netbox_site\" \"test\" {\n  name   = \"%[1]s\"\n  status = \"active\"\n}\n\nresource \"netbox_vlan_group\" \"test_group\" {\n  name       = \"%[1]s\"\n  slug       = \"%[1]s\"\n  scope_type = \"dcim.site\"\n  scope_id   = netbox_site.test.id\n  vid_ranges = [[1, 4094]]\n}\n\nresource \"netbox_vlan\" \"test\" {\n  name      = \"%[1]s\"\n  vid       = 777\n  status    = \"active\"\n  tenant_id = netbox_tenant.test.id\n  site_id   = netbox_site.test.id\n  group_id  = netbox_vlan_group.test_group.id\n}\n\nresource \"netbox_wireless_lan_group\" \"test\" {\n  name = \"%[1]s\"\n}`, testName)\n}\n\nfunc TestAccNetboxWirelessLAN_basic(t *testing.T) {\n\ttestSlug := \"wlan_basic\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: fmt.Sprintf(`\nresource \"netbox_wireless_lan\" \"test\" {\n  ssid = \"%s\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"ssid\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"tags.#\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:      \"netbox_wireless_lan.test\",\n\t\t\t\tImportState:       true,\n\t\t\t\tImportStateVerify: true,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxWirelessLAN_withDependencies(t *testing.T) {\n\ttestSlug := \"wlan_with_deps\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxWirelessLANDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_wireless_lan\" \"test\" {\n  ssid        = \"%[1]s\"\n  status      = \"reserved\"\n  group_id    = netbox_wireless_lan_group.test.id\n  tenant_id   = netbox_tenant.test.id\n  vlan_id     = netbox_vlan.test.id\n  auth_type   = \"wpa-personal\"\n  auth_cipher = \"aes\"\n  auth_psk    = \"supersecret123\"\n  description = \"test description\"\n  comments    = \"test comments\"\n  tags        = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"ssid\", testName),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"status\", \"reserved\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"auth_type\", \"wpa-personal\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"auth_cipher\", \"aes\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"description\", \"test description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"comments\", \"test comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_wireless_lan.test\", \"group_id\", \"netbox_wireless_lan_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_wireless_lan.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_wireless_lan.test\", \"vlan_id\", \"netbox_vlan.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"tags.#\", \"1\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"tags.0\", testName),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tResourceName:            \"netbox_wireless_lan.test\",\n\t\t\t\tImportState:             true,\n\t\t\t\tImportStateVerify:       true,\n\t\t\t\tImportStateVerifyIgnore: []string{\"auth_psk\"},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestAccNetboxWirelessLAN_clearOptionalFields(t *testing.T) {\n\ttestSlug := \"wlan_clear_opts\"\n\ttestName := testAccGetTestName(testSlug)\n\tresource.ParallelTest(t, resource.TestCase{\n\t\tProviders: testAccProviders,\n\t\tPreCheck:  func() { testAccPreCheck(t) },\n\t\tSteps: []resource.TestStep{\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxWirelessLANDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_wireless_lan\" \"test\" {\n  ssid        = \"%[1]s\"\n  status      = \"reserved\"\n  group_id    = netbox_wireless_lan_group.test.id\n  tenant_id   = netbox_tenant.test.id\n  vlan_id     = netbox_vlan.test.id\n  auth_type   = \"wpa-personal\"\n  auth_cipher = \"aes\"\n  auth_psk    = \"supersecret123\"\n  description = \"test description\"\n  comments    = \"test comments\"\n  tags        = [netbox_tag.test.name]\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"status\", \"reserved\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"auth_type\", \"wpa-personal\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"auth_cipher\", \"aes\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"description\", \"test description\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"comments\", \"test comments\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_wireless_lan.test\", \"group_id\", \"netbox_wireless_lan_group.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_wireless_lan.test\", \"tenant_id\", \"netbox_tenant.test\", \"id\"),\n\t\t\t\t\tresource.TestCheckResourceAttrPair(\"netbox_wireless_lan.test\", \"vlan_id\", \"netbox_vlan.test\", \"id\"),\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tConfig: testAccNetboxWirelessLANDependencies(testName) + fmt.Sprintf(`\nresource \"netbox_wireless_lan\" \"test\" {\n  ssid   = \"%[1]s\"\n  status = \"active\"\n}`, testName),\n\t\t\t\tCheck: resource.ComposeTestCheckFunc(\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"status\", \"active\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"auth_type\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"auth_cipher\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"auth_psk\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"description\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"comments\", \"\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"group_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"tenant_id\", \"0\"),\n\t\t\t\t\tresource.TestCheckResourceAttr(\"netbox_wireless_lan.test\", \"vlan_id\", \"0\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "netbox/slug_test.go",
    "content": "package netbox\n\nimport (\n\t\"testing\"\n)\n\nfunc TestSlugGeneration(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname, input, expected string\n\t}{\n\t\t{\n\t\t\tname:     \"LowerCase\",\n\t\t\tinput:    \"FOO\",\n\t\t\texpected: \"foo\",\n\t\t},\n\t\t{\n\t\t\tname:     \"SpecialChars\",\n\t\t\tinput:    `f^o!o\"§$%&/-_()=?b`,\n\t\t\texpected: \"foo-_b\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Multidash\",\n\t\t\tinput:    \"--d-a---s---h------\",\n\t\t\texpected: \"d-a-s-h\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Trailing\",\n\t\t\tinput:    \"foo&  $\",\n\t\t\texpected: \"foo\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Full\",\n\t\t\tinput:    \"Foo & 33 bar -- yes-\",\n\t\t\texpected: \"foo-33-bar-yes\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual := getSlug(tt.input)\n\t\t\tif actual != tt.expected {\n\t\t\t\tt.Fatalf(\"\\n\\nexpected:\\n\\n%#v\\n\\ngot:\\n\\n%#v\\n\\n\", tt.expected, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "netbox/slugs.go",
    "content": "package netbox\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n)\n\nfunc getSlug(name string) string {\n\tvar result string\n\t// \\w = word characters (== [0-9A-Za-z_])\n\t// \\s = whitespace (== [\\t\\n\\f\\r ])\n\tmatchSpecial, _ := regexp.Compile(`[^\\w\\s-]`)\n\tmatchMultiWhitespacesAndDashes, _ := regexp.Compile(`[\\s-]+`)\n\t// Special chars are stripped\n\tresult = matchSpecial.ReplaceAllString(name, \"\")\n\t// Blocks of multiple whitespaces and dashes will be replaced by a single dash\n\tresult = matchMultiWhitespacesAndDashes.ReplaceAllString(result, \"-\")\n\tresult = strings.Trim(result, \"-\")\n\treturn strings.ToLower(result)\n}\n"
  },
  {
    "path": "netbox/tags.go",
    "content": "package netbox\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/client\"\n\t\"github.com/fbreckle/go-netbox/netbox/client/extras\"\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nconst (\n\ttagsKey    = \"tags\"\n\ttagsAllKey = \"tags_all\"\n)\n\nvar tagsSchema = &schema.Schema{\n\tType: schema.TypeSet,\n\tElem: &schema.Schema{\n\t\tType: schema.TypeString,\n\t},\n\tOptional: true,\n\tSet:      schema.HashString,\n}\n\nvar tagsAllSchema = &schema.Schema{\n\tType: schema.TypeSet,\n\tElem: &schema.Schema{\n\t\tType: schema.TypeString,\n\t},\n\tComputed: true,\n\tSet:      schema.HashString,\n}\n\nvar tagsSchemaRead = &schema.Schema{\n\tType: schema.TypeSet,\n\tElem: &schema.Schema{\n\t\tType: schema.TypeString,\n\t},\n\tComputed: true,\n\tSet:      schema.HashString,\n}\n\nfunc getNestedTagListFromResourceDataSet(state *providerState, d interface{}) ([]*models.NestedTag, error) {\n\ttagList := d.(*schema.Set).List()\n\ttags := []*models.NestedTag{}\n\tfor _, tag := range tagList {\n\t\tnbTag, ok := state.tagCache[tag.(string)]\n\t\tif !ok {\n\t\t\tvar err error\n\t\t\tnbTag, err = findTag(state.NetBoxAPI, tag.(string))\n\t\t\tif err != nil {\n\t\t\t\treturn tags, err\n\t\t\t}\n\t\t}\n\n\t\ttags = append(tags, nbTag)\n\t}\n\n\treturn tags, nil\n}\n\nfunc findTag(client *client.NetBoxAPI, name string) (*models.NestedTag, error) {\n\tparams := extras.NewExtrasTagsListParams()\n\tparams.Name = &name\n\n\tlimit := int64(2) // We search for a unique tag. Having two hits suffices to know its not unique.\n\tparams.Limit = &limit\n\n\tres, err := client.Extras.ExtrasTagsList(params, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"API Error trying to retrieve tag %q from netbox: %w\", name, err)\n\t}\n\n\tpayload := res.GetPayload()\n\tswitch *payload.Count {\n\tcase int64(0):\n\t\treturn nil, fmt.Errorf(\"could not locate referenced tag %q in netbox, no results\", name)\n\tcase int64(1):\n\t\treturn &models.NestedTag{\n\t\t\tName: payload.Results[0].Name,\n\t\t\tSlug: payload.Results[0].Slug,\n\t\t}, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"could not map tag %q to unique tag in netbox, %d results\", name, *payload.Count)\n\t}\n}\n\nfunc getTagListFromNestedTagList(nestedTags []*models.NestedTag) []string {\n\ttags := []string{}\n\tfor _, nestedTag := range nestedTags {\n\t\ttags = append(tags, *nestedTag.Name)\n\t}\n\treturn tags\n}\n\nfunc (s *providerState) readTags(d *schema.ResourceData, apiTags []*models.NestedTag) {\n\tallTags := schema.NewSet(schema.HashString, nil)\n\tfor _, t := range apiTags {\n\t\tallTags.Add(*t.Name)\n\t}\n\td.Set(tagsAllKey, allTags.List())\n\n\tconfigTags := make([]string, len(apiTags))\n\tcf := d.GetRawConfig()\n\tif cf.IsNull() || !cf.IsKnown() {\n\t\tcf = d.GetRawState() // config is missing during refresh\n\t}\n\tif !cf.IsNull() && cf.IsKnown() { // there is some config\n\t\tc := cf.GetAttr(tagsKey)\n\t\tif !c.IsNull() && c.IsKnown() { // tags are configured\n\t\t\tfor _, t := range c.AsValueSet().Values() {\n\t\t\t\tconfigTags = append(configTags, t.AsString())\n\t\t\t}\n\t\t}\n\t}\n\n\tresourceTags := schema.NewSet(schema.HashString, nil)\n\t// remove default tags (except when configured on the resource)\n\tfor _, tag := range apiTags {\n\t\tif !s.defaultTags.Contains(*tag.Name) || slices.Contains(configTags, *tag.Name) {\n\t\t\tresourceTags.Add(*tag.Name)\n\t\t}\n\t}\n\n\td.Set(tagsKey, resourceTags.List())\n}\n"
  },
  {
    "path": "netbox/tags_test.go",
    "content": "package netbox\n\nimport (\n\t\"testing\"\n\n\t\"github.com/fbreckle/go-netbox/netbox/models\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGetTagListFromNestedTagList(t *testing.T) {\n\ttags := []*models.NestedTag{\n\t\t{\n\t\t\tName: strToPtr(\"Foo\"),\n\t\t\tSlug: strToPtr(\"foo\"),\n\t\t},\n\t\t{\n\t\t\tName: strToPtr(\"Bar\"),\n\t\t\tSlug: strToPtr(\"bar\"),\n\t\t},\n\t}\n\n\tflat := getTagListFromNestedTagList(tags)\n\texpected := []string{\n\t\t\"Foo\",\n\t\t\"Bar\",\n\t}\n\tassert.Equal(t, flat, expected)\n}\n"
  },
  {
    "path": "netbox/util.go",
    "content": "package netbox\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema\"\n)\n\nfunc strToPtr(str string) *string {\n\treturn &str\n}\n\nfunc int64ToPtr(i int64) *int64 {\n\treturn &i\n}\n\nfunc float64ToPtr(i float64) *float64 {\n\treturn &i\n}\n\nfunc toStringList(a interface{}) []string {\n\tstrList := []string{}\n\tfor _, str := range a.(*schema.Set).List() {\n\t\tstrList = append(strList, str.(string))\n\t}\n\treturn strList\n}\n\nfunc toInt64List(a interface{}) []int64 {\n\tintList := []int64{}\n\tfor _, number := range a.(*schema.Set).List() {\n\t\tif n, ok := number.(int); ok {\n\t\t\tintList = append(intList, int64(n))\n\t\t} else if n, ok := number.(int64); ok {\n\t\t\tintList = append(intList, n)\n\t\t}\n\t}\n\treturn intList\n}\n\nfunc toInt64PtrList(a interface{}) []*int64 {\n\tintList := []*int64{}\n\tif set, ok := a.(*schema.Set); ok {\n\t\tfor _, number := range set.List() {\n\t\t\tif n, ok := number.(int); ok {\n\t\t\t\tintList = append(intList, int64ToPtr(int64(n)))\n\t\t\t} else if n, ok := number.(int64); ok {\n\t\t\t\tintList = append(intList, int64ToPtr(n))\n\t\t\t}\n\t\t}\n\t}\n\treturn intList\n}\n\nfunc joinStringWithFinalConjunction(elems []string, sep, con string) string {\n\tswitch len(elems) {\n\tcase 0:\n\t\treturn \"\"\n\tcase 1:\n\t\treturn elems[0]\n\t}\n\n\tvar b strings.Builder\n\tb.WriteString(strings.Join(elems[0:len(elems)-1], sep))\n\tfmt.Fprintf(&b, \" %s %s\", con, elems[len(elems)-1])\n\treturn b.String()\n}\n\nfunc buildValidValueDescription(options []string) string {\n\tvar quoted []string\n\tfor _, option := range options {\n\t\tquoted = append(quoted, fmt.Sprintf(\"`%s`\", option))\n\t}\n\treturn \"Valid values are \" + joinStringWithFinalConjunction(quoted, \", \", \"and\")\n}\n\nfunc getOptionalStr(d *schema.ResourceData, key string, useSpace bool) string {\n\tstrVal := \"\"\n\t// check if key is set\n\tstrValInterface, ok := d.GetOk(key)\n\tif ok || d.HasChange(key) {\n\t\tif !ok && useSpace {\n\t\t\t// Setting an space string deletes the value\n\t\t\t// Ideally we would have the ability to determine if a struct value was set to the zero-value or not\n\t\t\t// The API often supports setting null to clear a value, but this is a Go/Swagger limitation\n\t\t\tstrVal = \" \"\n\t\t} else if ok {\n\t\t\tstrVal = strValInterface.(string)\n\t\t}\n\t}\n\treturn strVal\n}\n\nfunc getOptionalVal[SchemaT int | float64, ApiT int64 | float64](d *schema.ResourceData, key string) *ApiT {\n\tvar apiPtr *ApiT\n\tschemaValIf, ok := d.GetOk(key)\n\tif ok {\n\t\tschemaVal, _ := schemaValIf.(SchemaT)\n\t\tapiVal := ApiT(schemaVal)\n\t\tapiPtr = &apiVal\n\t}\n\treturn apiPtr\n}\n\nfunc getOptionalInt(d *schema.ResourceData, key string) *int64 {\n\treturn getOptionalVal[int, int64](d, key)\n}\n\nfunc getOptionalFloat(d *schema.ResourceData, key string) *float64 {\n\treturn getOptionalVal[float64, float64](d, key)\n}\n\n// jsonSemanticCompare returns true when 2 json strings encode the same\n// structure, regardless of whitespace differences. This can be used in\n// DiffSuppressFunc implementations to prevent terraform showing whitespace\n// changes as differences on refresh.\nfunc jsonSemanticCompare(a, b string) (equal bool, err error) {\n\tvar aDecoded, bDecoded any\n\n\terr = json.Unmarshal([]byte(a), &aDecoded)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"could not decode a: %w\", err)\n\t}\n\n\terr = json.Unmarshal([]byte(b), &bDecoded)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"could not decode b: %w\", err)\n\t}\n\n\treturn reflect.DeepEqual(aDecoded, bDecoded), nil\n}\n\n// extractNetboxVersionFromString extracts the first semantic versioning string\n// from a given string. The string must be preceded with \"v\".\n// This is needed since netbox-docker recently started displaying its version string\n// as, for example, v4.2.8-Docker-3.2.1 and we want to ignore the Docker part\n// ref: https://github.com/e-breuninger/terraform-provider-netbox/issues/729\nfunc extractSemanticVersionFromString(s string) (version string, err error) {\n\tre := regexp.MustCompile(`^v?(\\d+\\.\\d+\\.\\d+)`)\n\n\tmatches := re.FindStringSubmatch(s)\n\tif len(matches) < 2 {\n\t\treturn \"\", fmt.Errorf(\"no semantic version found in version string\")\n\t}\n\treturn matches[1], nil\n}\n"
  },
  {
    "path": "netbox/util_test.go",
    "content": "package netbox\n\nimport (\n\t\"testing\"\n)\n\nfunc TestJoinStringWithFinalConjunction(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tlist     []string\n\t\tsep      string\n\t\tcon      string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"Full\",\n\t\t\tlist:     []string{\"foo\", \"bar\", \"baz\"},\n\t\t\tsep:      \", \",\n\t\t\tcon:      \"and\",\n\t\t\texpected: \"foo, bar and baz\",\n\t\t},\n\t\t{\n\t\t\tname:     \"OnlyTwoItems\",\n\t\t\tlist:     []string{\"foo\", \"bar\"},\n\t\t\tsep:      \", \",\n\t\t\tcon:      \"and\",\n\t\t\texpected: \"foo and bar\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual := joinStringWithFinalConjunction(tt.list, tt.sep, tt.con)\n\t\t\tif actual != tt.expected {\n\t\t\t\tt.Fatalf(\"\\n\\nexpected:\\n\\n%#v\\n\\ngot:\\n\\n%#v\\n\\n\", tt.expected, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestBuildValidValueDescription(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tlist     []string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"Full\",\n\t\t\tlist:     []string{\"foo\", \"bar\", \"baz\"},\n\t\t\texpected: \"Valid values are `foo`, `bar` and `baz`\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual := buildValidValueDescription(tt.list)\n\t\t\tif actual != tt.expected {\n\t\t\t\tt.Fatalf(\"\\n\\nexpected:\\n\\n%#v\\n\\ngot:\\n\\n%#v\\n\\n\", tt.expected, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestJsonSemanticCompareEqual(t *testing.T) {\n\ta := `{\"a\": [{ \"b\": [1, 2, 3]}]}`\n\tb := `{\"a\":[{\"b\":[1,2,3]}]}`\n\n\tequal, err := jsonSemanticCompare(a, b)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif !equal {\n\t\tt.Errorf(\"expected 'a' and 'b' to be semantically equal\\n\\na: %s\\nb: %s\\n\", a, b)\n\t}\n}\n\nfunc TestJsonSemanticCompareUnequal(t *testing.T) {\n\ta := `{\"a\": [{ \"b\": [1, 2, 3]}]}`\n\tb := `{\"a\": [{ \"b\": [1, 2, 4]}]}`\n\n\tequal, err := jsonSemanticCompare(a, b)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif equal {\n\t\tt.Errorf(\"expected 'a' and 'b' to be semantically unequal\\n\\na: %s\\nb: %s\\n\", a, b)\n\t}\n}\n\nfunc TestExtractSemanticVersionFromString(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"Incomplete\",\n\t\t\tinput:    \"v1.3\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"SimpleWithV\",\n\t\t\tinput:    \"v1.2.3\",\n\t\t\texpected: \"1.2.3\",\n\t\t},\n\t\t{\n\t\t\tname:     \"SimpleWithoutV\",\n\t\t\tinput:    \"1.2.3\",\n\t\t\texpected: \"1.2.3\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Docker\",\n\t\t\tinput:    \"v4.5.6-Docker-3.2\",\n\t\t\texpected: \"4.5.6\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, _ := extractSemanticVersionFromString(tt.input)\n\t\t\tif actual != tt.expected {\n\t\t\t\tt.Fatalf(\"\\n\\nexpected:\\n\\n%#v\\n\\ngot:\\n\\n%#v\\n\\n\", tt.expected, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "netbox/validation.go",
    "content": "package netbox\n\nimport \"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation\"\n\nconst (\n\tmaxUint16 = ^uint16(0)\n\tmaxInt16  = int(maxUint16 >> 1)\n\n\tmaxUint32 = ^uint32(0)\n\tmaxInt32  = int(maxUint32 >> 1)\n)\n\nvar (\n\tvalidatePositiveInt16 = validation.IntBetween(0, maxInt16)\n\tvalidatePositiveInt32 = validation.IntBetween(0, maxInt32)\n)\n"
  },
  {
    "path": "scripts/allowed_subcategories.sh",
    "content": "#!/bin/bash\n\n# This script makes sure that we do not accidentally introduce a new subcategory in the docs\n# Each subcategory is rendered as a separate list in the docs page at https://registry.terraform.io/providers/e-breuninger/netbox/latest/docs\n# The list in the docs should be concise, not cluttered with typos or other inadvertent subcategories\n#\n# The list of allowed subcategories is maintained in a file (see below)\n\nreadonly allowfilepath=\".github/allowed-subcategories.txt\"\n\nwhile read -r line; do\n    if ! grep --quiet \"$line\" \"$allowfilepath\"; then\n        echo \"error: subcategory \\\"$line\\\" is not in $allowfilepath\"\n        exit 1\n    fi\ndone <<<\"$(grep --no-filename --recursive subcategory docs | sort --unique | cut --delimiter='\"' --fields=2)\"\n"
  },
  {
    "path": "scripts/ensure_docs_examples.sh",
    "content": "#!/bin/bash\n\nexitcode=0\n\nresources=\"$(grep \"resource.*(),\" netbox/provider.go | sed 's/.*\"\\(.*\\)\":.*/\\1/')\"\n\nfor resource in ${resources}; do\n    ls -1 examples/resources/\"$resource\"/*.tf >/dev/null 2>&1\n    # ls has exitcode 2 if no files are found\n    if [ \"$?\" = \"2\" ]; then\n        echo \"Resource $resource has no example\"\n        exitcode=1\n    fi\ndone\n\n# Code for data source examples. Currently not used.\n#datasources=\"$(grep \"dataSource.*(),\" netbox/provider.go | sed 's/.*\"\\(.*\\)\":.*/\\1/')\"\n#\n#for datasource in ${datasources}; do\n#    ls -1 examples/data-sources/\"$datasource\"/*.tf >/dev/null 2>&1\n#    if [ \"$?\" = \"2\" ]; then\n#        echo \"Data source $datasource has no example\"\n#        exitcode=1\n#    fi\n#done\n\nexit $exitcode\n"
  },
  {
    "path": "templates/index.md.tmpl",
    "content": "---\nlayout: \"\"\npage_title: \"Provider: Netbox\"\ndescription: |-\n  The netbox provider provides resources and data sources to interact with Netbox.\n---\n\n# Netbox Provider\n\nThe Terraform Netbox provider is a plugin for Terraform that allows for the full lifecycle management of [Netbox](https://netboxlabs.com/docs/netbox/) resources.\n\nUse the navigation to the left to read about the available resources.\n\n## Supported Netbox versions\nNetbox often makes breaking API changes even in non-major releases. Check the table below to see which version this provider is compatible with your Netbox version. It is generally recommended to use the provider version matching your Netbox version.\n\n| Netbox version  | Provider version |\n| --------------- | ---------------- |\n| v4.3.0 - 4.4.10 | v5.0.0 and up    |\n| v4.2.2 - 4.2.9  | v4.0.0 - 4.3.1   |\n| v4.1.0 - 4.1.11 | v3.10.0 - 3.11.1 |\n| v4.0.0 - 4.0.11 | v3.9.0 - 3.9.2   |\n| v3.7.0 - 3.7.8  | v3.8.0 - 3.8.9   |\n| v3.6.0 - 3.6.9  | v3.7.0 - 3.7.7   |\n| v3.5.1 - 3.5.9  | v3.6.x           |\n| v3.4.3 - 3.4.10 | v3.5.x           |\n| v3.3.0 - 3.4.2  | v3.0.x - 3.5.1   |\n| v3.2.0 - 3.2.9  | v2.0.x           |\n| v3.1.9          | v1.6.0 - 1.6.7   |\n| v3.1.3          | v1.1.x - 1.5.2   |\n| v3.0.9          | v1.0.x           |\n| v2.11.12        | v0.3.x           |\n| v2.10.10        | v0.2.x           |\n| v2.9            | v0.1.x           |\n\nAdditionally, since version [1.6.6](https://github.com/e-breuninger/terraform-provider-netbox/commit/0b0b2fffa54d4ab2e5f1677e948b01e56ba211c8), each version of the provider has a built-in list of all Netbox versions it supports at release time. Upon initialization, the provider will probe your Netbox version and include a (non-blocking) warning if the used Netbox version is not supported.\n\n## Configuration\nYou must configure the provider with proper credentials before you can use it. You can configure the provider via attributes in the provider block or via environment variables. See [Schema](#schema) for all configuration options\n\n## Example Usage\n\n{{tffile \"examples/provider/provider.tf\"}}\n\n{{ .SchemaMarkdown | trimspace }}\n"
  },
  {
    "path": "templates/resources/available_ip_address.md.tmpl",
    "content": "---\npage_title: \"{{.Name}} {{.Type}} - {{.ProviderName}}\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n{{ .Description | plainmarkdown | trimspace | prefixlines \"  \" }}\n---\n\n# {{.Name}} ({{.Type}})\n\n{{ .Description | trimspace }}\n\n## Example Usage\n### Creating an IP in a prefix\n{{ tffile \"examples/resources/netbox_available_ip_address/prefix.tf\" }}\n\n### Creating an IP in an IP range\n{{ tffile \"examples/resources/netbox_available_ip_address/range.tf\" }}\n\n### Marking an IP active and assigning to interface\n{{ tffile \"examples/resources/netbox_available_ip_address/assign_to_interface.tf\" }}\n\n{{ .SchemaMarkdown | trimspace }}\n\n{{ if .HasImport -}}\n## Import\n\nImport is supported using the following syntax:\n\n{{ printf \"{{codefile \\\"shell\\\" %q}}\" .ImportFile }}\n{{- end }}\n"
  },
  {
    "path": "templates/resources/ip_address.md.tmpl",
    "content": "---\npage_title: \"{{.Name}} {{.Type}} - {{.ProviderName}}\"\nsubcategory: \"IP Address Management (IPAM)\"\ndescription: |-\n{{ .Description | plainmarkdown | trimspace | prefixlines \"  \" }}\n---\n\n# {{.Name}} ({{.Type}})\n\n{{ .Description | trimspace }}\n\n## Example Usage\n\n### Creating an IP address that is assigned to a virtual machine interface\n\nStarting with provider version 3.5.0, you can use the `virtual_machine_interface_id` attribute to assign an IP address to a virtual machine interface.\nYou can also use the `interface_id` and `object_type` attributes instead.\n\nWith `virtual_machine_interface_id`:\n{{ tffile \"examples/resources/netbox_ip_address/virtual_machine_interface_id.tf\" }}\n\nWith `object_type` and `interface_id`:\n{{ tffile \"examples/resources/netbox_ip_address/object_type_virtual_machine.tf\" }}\n\n### Creating an IP address that is assigned to a device interface\n\nStarting with provider version 3.5.0, you can use the `device_interface_id` attribute to assign an IP address to a device interface.\nYou can also use the `interface_id` and `object_type` attributes instead.\n\nWith `device_interface_id`:\n{{ tffile \"examples/resources/netbox_ip_address/device_interface_id.tf\" }}\n\nWith `object_type` and `interface_id`:\n{{ tffile \"examples/resources/netbox_ip_address/object_type_device.tf\" }}\n\n### Creating an IP address that is not assigned to anything\n\nYou can create an IP address that is not assigned to anything by omitting the attributes mentioned above.\n\n{{ tffile \"examples/resources/netbox_ip_address/standalone.tf\" }}\n\n{{ .SchemaMarkdown | trimspace }}\n\n{{ if .HasImport -}}\n## Import\n\nImport is supported using the following syntax:\n\n{{ printf \"{{codefile \\\"shell\\\" %q}}\" .ImportFile }}\n{{- end }}\n"
  },
  {
    "path": "templates/resources/mac_address.md.tmpl",
    "content": "---\npage_title: \"{{.Name}} {{.Type}} - {{.ProviderName}}\"\nsubcategory: \"Data Center Inventory Management (DCIM)\"\ndescription: |-\n{{ .Description | plainmarkdown | trimspace | prefixlines \"  \" }}\n---\n\n# {{.Name}} ({{.Type}})\n\n{{ .Description | trimspace }}\n\n## Example Usage\n\n### Creating a MAC address that is assigned to a virtual machine interface\n\nWith `virtual_machine_interface_id`:\n{{ tffile \"examples/resources/netbox_mac_address/virtual_machine_interface_id.tf\" }}\n\nWith `object_type` and `interface_id`:\n{{ tffile \"examples/resources/netbox_mac_address/object_type_virtual_machine.tf\" }}\n\n### Creating a MAC address that is assigned to a device interface\n\nWith `device_interface_id`:\n{{ tffile \"examples/resources/netbox_mac_address/device_interface_id.tf\" }}\n\nWith `object_type` and `interface_id`:\n{{ tffile \"examples/resources/netbox_mac_address/object_type_device.tf\" }}\n\n### Creating a MAC address that is not assigned to anything\n\nYou can create a MAC address that is not assigned to anything by omitting the attributes mentioned above.\n\n{{ tffile \"examples/resources/netbox_mac_address/standalone.tf\" }}\n\n{{ .SchemaMarkdown | trimspace }}\n\n{{ if .HasImport -}}\n## Import\n\nImport is supported using the following syntax:\n\n{{ printf \"{{codefile \\\"shell\\\" %q}}\" .ImportFile }}\n{{- end }}\n"
  },
  {
    "path": "tools/tools.go",
    "content": "// +build tools\n\npackage tools\n\nimport (\n\t// document generation\n\t_ \"github.com/fbreckle/terraform-plugin-docs/cmd/tfplugindocs\"\n)\n"
  }
]