├── .changes
├── 2.2.0.md
├── 2.3.0.md
├── 2.3.1.md
├── 2.3.2.md
├── 2.3.3.md
├── 2.3.4.md
├── 2.3.5.md
├── 2.3.6-alpha1.md
├── 2.3.6.md
├── 2.3.7-alpha1.md
├── 2.3.7.md
└── unreleased
│ └── .gitkeep
├── .changie.yaml
├── .copywrite.hcl
├── .github
├── CODEOWNERS
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── Bug_Report.yml
│ ├── Feature_Request.yml
│ └── config.yml
├── SUPPORT.md
├── dependabot.yml
├── labeler-issue-triage.yml
├── labeler-pull-request-triage.yml
├── pull_request_template.md
└── workflows
│ ├── build.yml
│ ├── ci-changie.yml
│ ├── compliance.yml
│ ├── issue-comment-triage.yml
│ ├── issue-opened.yml
│ ├── lock.yml
│ ├── pull-request.yml
│ └── test.yml
├── .gitignore
├── .golangci.yml
├── .release
├── ci.hcl
├── release-metadata.hcl
├── security-scan.hcl
└── terraform-provider-cloudinit-artifacts.hcl
├── CHANGELOG.md
├── DESIGN.md
├── GNUmakefile
├── LICENSE
├── META.d
└── _summary.yaml
├── README.md
├── docs
├── cdktf
│ ├── python
│ │ ├── data-sources
│ │ │ └── config.md
│ │ ├── index.md
│ │ └── resources
│ │ │ └── config.md
│ └── typescript
│ │ ├── data-sources
│ │ └── config.md
│ │ ├── index.md
│ │ └── resources
│ │ └── config.md
├── data-sources
│ └── config.md
├── index.md
└── resources
│ └── config.md
├── examples
├── data-sources
│ └── cloudinit_config
│ │ ├── cloud-config.yaml
│ │ ├── data-source.tf
│ │ └── hello-script.sh
└── resources
│ └── cloudinit_config
│ ├── cloud-config.yaml
│ ├── hello-script.sh
│ └── resource.tf
├── go.mod
├── go.sum
├── internal
├── hashcode
│ ├── hashcode.go
│ └── hashcode_test.go
└── provider
│ ├── cloudinit_config.go
│ ├── data_source_cloudinit_config.go
│ ├── data_source_cloudinit_config_test.go
│ ├── provider.go
│ ├── provider_test.go
│ ├── resource_cloudinit_config.go
│ └── resource_cloudinit_config_test.go
├── main.go
├── templates
├── data-sources
│ └── config.md.tmpl
├── index.md.tmpl
└── resources
│ └── config.md.tmpl
├── terraform-registry-manifest.json
├── tools
├── go.mod
├── go.sum
└── tools.go
└── version
└── VERSION
/.changes/2.2.0.md:
--------------------------------------------------------------------------------
1 | ## 2.2.0 (February 19, 2021)
2 |
3 | Binary releases of this provider will now include the darwin-arm64 platform. This version contains no further changes.
4 |
5 | ## 2.1.0 (November 26, 2020)
6 |
7 | NEW FEATURES:
8 |
9 | * MIMEBOUNDARY can now be customised with `boundary` ([#7](https://github.com/hashicorp/terraform-provider-cloudinit/issues/7)).
10 |
11 | ## 2.0.0 (October 12, 2020)
12 |
13 | Binary releases of this provider will now include the linux-arm64 platform.
14 |
15 | BREAKING CHANGES:
16 |
17 | * Upgrade to version 2 of the Terraform Plugin SDK, which drops support for Terraform 0.11. This provider will continue to work as expected for users of Terraform 0.11, which will not download the new version. ([#3](https://github.com/hashicorp/terraform-provider-cloudinit/issues/3))
18 |
19 | ## 1.0.0 (April 14, 2020)
20 |
21 | Initial release. This provider exposes one resource, cloudinit_config, which is identical to the template_cloudinit_config resource in terraform-provider-template.
22 |
--------------------------------------------------------------------------------
/.changes/2.3.0.md:
--------------------------------------------------------------------------------
1 | ## 2.3.0 (February 22, 2023)
2 |
3 | NOTES:
4 |
5 | * provider: Rewritten to use the [`terraform-plugin-framework`](https://www.terraform.io/plugin/framework) ([#96](https://github.com/hashicorp/terraform-provider-cloudinit/issues/96))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.1.md:
--------------------------------------------------------------------------------
1 | ## 2.3.1 (February 22, 2023)
2 |
3 | BUG FIXES:
4 |
5 | * cloudinit_config: Fixed handling of unknown values in `part` blocks ([#103](https://github.com/hashicorp/terraform-provider-cloudinit/issues/103))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.2.md:
--------------------------------------------------------------------------------
1 | ## 2.3.2 (February 23, 2023)
2 |
3 | BUG FIXES:
4 |
5 | * cloudinit_config: Remove length validation to allow empty content string in part blocks ([#105](https://github.com/hashicorp/terraform-provider-cloudinit/issues/105))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.3.md:
--------------------------------------------------------------------------------
1 | ## 2.3.3 (November 29, 2023)
2 |
3 | NOTES:
4 |
5 | * This release introduces no functional changes. It does however include dependency updates which address upstream CVEs. ([#186](https://github.com/hashicorp/terraform-provider-cloudinit/issues/186))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.4.md:
--------------------------------------------------------------------------------
1 | ## 2.3.4 (April 22, 2024)
2 |
3 | NOTES:
4 |
5 | * all: This release contains no functionality changes, only the inclusion of the LICENSE file in the release archives ([#228](https://github.com/hashicorp/terraform-provider-cloudinit/issues/228))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.5.md:
--------------------------------------------------------------------------------
1 | ## 2.3.5 (September 10, 2024)
2 |
3 | NOTES:
4 |
5 | * all: This release introduces no functional changes. It does however include dependency updates which address upstream CVEs. ([#263](https://github.com/hashicorp/terraform-provider-cloudinit/issues/263))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.6-alpha1.md:
--------------------------------------------------------------------------------
1 | ## 2.3.6-alpha1 (December 05, 2024)
2 |
3 | NOTES:
4 |
5 | * all: This release contains no functionality changes. It is released using new build and release Actions. ([#293](https://github.com/hashicorp/terraform-provider-cloudinit/issues/293))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.6.md:
--------------------------------------------------------------------------------
1 | ## 2.3.6 (February 27, 2025)
2 |
3 | NOTES:
4 |
5 | * all: This release contains no functionality changes. It is being used to fix release metadata in the registry from the previous alpha1 release. ([#318](https://github.com/hashicorp/terraform-provider-cloudinit/issues/318))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.7-alpha1.md:
--------------------------------------------------------------------------------
1 | ## 2.3.7-alpha1 (March 04, 2025)
2 |
3 | NOTES:
4 |
5 | * all: This release is being used to test new build and release actions.
6 |
7 |
--------------------------------------------------------------------------------
/.changes/2.3.7.md:
--------------------------------------------------------------------------------
1 | ## 2.3.7 (April 21, 2025)
2 |
3 | NOTES:
4 |
5 | * Update dependencies ([#339](https://github.com/hashicorp/terraform-provider-cloudinit/issues/339))
6 |
7 |
--------------------------------------------------------------------------------
/.changes/unreleased/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hashicorp/terraform-provider-cloudinit/d0453b832c2d51f01177f323218afe7249b9ab8e/.changes/unreleased/.gitkeep
--------------------------------------------------------------------------------
/.changie.yaml:
--------------------------------------------------------------------------------
1 | # DO NOT EDIT - This GitHub Workflow is managed by automation
2 | # https://github.com/hashicorp/terraform-devex-repos
3 | changesDir: .changes
4 | unreleasedDir: unreleased
5 | changelogPath: CHANGELOG.md
6 | versionExt: md
7 | versionFormat: '## {{.Version}} ({{.Time.Format "January 02, 2006"}})'
8 | kindFormat: '{{.Kind}}:'
9 | changeFormat: '* {{.Body}} ([#{{.Custom.Issue}}](https://github.com/hashicorp/terraform-provider-cloudinit/issues/{{.Custom.Issue}}))'
10 | custom:
11 | - key: Issue
12 | label: Issue/PR Number
13 | type: int
14 | minInt: 1
15 | kinds:
16 | - label: BREAKING CHANGES
17 | - label: NOTES
18 | - label: FEATURES
19 | - label: ENHANCEMENTS
20 | - label: BUG FIXES
21 | newlines:
22 | afterKind: 1
23 | beforeKind: 1
24 | endOfVersion: 2
25 |
--------------------------------------------------------------------------------
/.copywrite.hcl:
--------------------------------------------------------------------------------
1 | schema_version = 1
2 |
3 | project {
4 | license = "MPL-2.0"
5 | copyright_year = 2019
6 |
7 | header_ignore = [
8 | # internal catalog metadata (prose)
9 | "META.d/**/*.yaml",
10 |
11 | # changie tooling configuration and CHANGELOG entries (prose)
12 | ".changes/unreleased/*.yaml",
13 | ".changie.yaml",
14 |
15 | # examples used within documentation (prose)
16 | "examples/**",
17 |
18 | # GitHub issue template configuration
19 | ".github/ISSUE_TEMPLATE/*.yml",
20 |
21 | # GitHub Actions workflow-specific configurations
22 | ".github/labeler-*.yml",
23 |
24 | # golangci-lint tooling configuration
25 | ".golangci.yml",
26 |
27 | # Release Engineering tooling configuration
28 | ".release/*.hcl",
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @hashicorp/terraform-core-plugins
2 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thank you for investing your time and energy by contributing to our project: please ensure you are familiar
4 | with the [HashiCorp Code of Conduct](https://github.com/hashicorp/.github/blob/master/CODE_OF_CONDUCT.md).
5 |
6 | This provider is a HashiCorp **utility provider**, which means any bug fix and feature
7 | has to be considered in the context of the thousands/millions of configurations in which this provider is used.
8 | This is great as your contribution can have a big positive impact, but we have to assess potential negative impact too
9 | (e.g. breaking existing configurations). _Stability over features_.
10 |
11 | To provide some safety to the wider provider ecosystem, we strictly follow
12 | [semantic versioning](https://semver.org/) and HashiCorp's own
13 | [versioning specification](https://www.terraform.io/plugin/sdkv2/best-practices/versioning#versioning-specification).
14 | Any changes that could be considered as breaking will only be included as part of a major release.
15 | In case multiple breaking changes need to happen, we will group them in the next upcoming major release.
16 |
17 | ## Asking Questions
18 |
19 | For questions, curiosity, or if still unsure what you are dealing with,
20 | please see the HashiCorp [Terraform Providers Discuss](https://discuss.hashicorp.com/c/terraform-providers/31)
21 | forum.
22 |
23 | ## Reporting Vulnerabilities
24 |
25 | Please disclose security vulnerabilities responsibly by following the
26 | [HashiCorp Vulnerability Reporting guidelines](https://www.hashicorp.com/security#vulnerability-reporting).
27 |
28 | ## Raising Issues
29 |
30 | We welcome issues of all kinds including feature requests, bug reports or documentation suggestions.
31 | Below are guidelines for well-formed issues of each type.
32 |
33 | ### Bug Reports
34 |
35 | * [ ] **Test against latest release**: Make sure you test against the latest available version of Terraform and the provider.
36 | It is possible we may have already fixed the bug you're experiencing.
37 | * [ ] **Search for duplicates**: It's helpful to keep bug reports consolidated to one thread, so do a quick search
38 | on existing bug reports to check if anybody else has reported the same thing.
39 | You can scope searches by the label `bug` to help narrow things down.
40 | * [ ] **Include steps to reproduce**: Provide steps to reproduce the issue, along with code examples and/or real code,
41 | so we can try to reproduce it. Without this, it makes it much harder (sometimes impossible) to fix the issue.
42 |
43 | ### Feature Requests
44 |
45 | * [ ] **Search for possible duplicate requests**: It's helpful to keep requests consolidated to one thread,
46 | so do a quick search on existing requests to check if anybody else has reported the same thing.
47 | You can scope searches by the label `enhancement` to help narrow things down.
48 | * [ ] **Include a use case description**: In addition to describing the behavior of the feature you'd like to see added,
49 | it's helpful to also make a case for why the feature would be important and how it would benefit
50 | the provider and, potentially, the wider Terraform ecosystem.
51 |
52 | ## New Pull Request
53 |
54 | Thank you for contributing!
55 |
56 | We are happy to review pull requests without associated issues,
57 | but we **highly recommend** starting by describing and discussing
58 | your problem or feature and attaching use cases to an issue first
59 | before raising a pull request.
60 |
61 | * [ ] **Early validation of idea and implementation plan**: provider development is complicated enough that there
62 | are often several ways to implement something, each of which has different implications and tradeoffs.
63 | Working through a plan of attack with the team before you dive into implementation will help ensure that you're
64 | working in the right direction.
65 | * [ ] **Tests**: It may go without saying, but every new patch should be covered by tests wherever possible.
66 | For bug-fixes, tests to prove the fix is valid. For features, tests to exercise the new code paths.
67 | * [ ] **Go Modules**: We use [Go Modules](https://github.com/golang/go/wiki/Modules) to manage and version our dependencies.
68 | Please make sure that you reflect dependency changes in your pull requests appropriately
69 | (e.g. `go get`, `go mod tidy` or other commands).
70 | Refer to the [dependency updates](#dependency-updates) section for more information about how
71 | this project maintains existing dependencies.
72 | * [ ] **Changelog**: Refer to the [changelog](#changelog) section for more information about how to create changelog entries.
73 | * [ ] **License Headers**: All source code requires a license header at the top of the file, refer to [License Headers](#license-headers) for information on how to autogenerate these headers.
74 |
75 | ### Dependency Updates
76 |
77 | Dependency management is performed by [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates).
78 | Where possible, dependency updates should occur through that system to ensure all Go module files are appropriately
79 | updated and to prevent duplicated effort of concurrent update submissions.
80 | Once available, updates are expected to be verified and merged to prevent latent technical debt.
81 |
82 | ### Changelog
83 |
84 | HashiCorp’s open-source projects have always maintained user-friendly, readable `CHANGELOG`s that allow
85 | practitioners and developers to tell at a glance whether a release should have any effect on them,
86 | and to gauge the risk of an upgrade.
87 |
88 | We follow Terraform Plugin
89 | [changelog specifications](https://www.terraform.io/plugin/sdkv2/best-practices/versioning#changelog-specification).
90 |
91 | #### Changie Automation Tool
92 | This provider uses the [Changie](https://changie.dev/) automation tool for changelog automation.
93 | To add a new entry to the `CHANGELOG` install Changie using the following [instructions](https://changie.dev/guide/installation/)
94 | and run
95 | ```bash
96 | changie new
97 | ```
98 | then choose a `kind` of change corresponding to the Terraform Plugin [changelog categories](https://developer.hashicorp.com/terraform/plugin/sdkv2/best-practices/versioning#categorization)
99 | and then fill out the body following the entry format. Changie will then prompt for a Github issue or pull request number.
100 | Repeat this process for any additional changes. The `.yaml` files created in the `.changes/unreleased` folder
101 | should be pushed the repository along with any code changes.
102 |
103 | #### Entry format
104 |
105 | Entries that are specific to _resources_ or _data sources_, they should look like:
106 |
107 | ```markdown
108 | * resource/RESOURCE_NAME: ENTRY DESCRIPTION
109 |
110 | * data-source/DATA-SOURCE_NAME: ENTRY DESCRIPTION
111 | ```
112 |
113 | #### Pull Request Types to `CHANGELOG`
114 |
115 | The `CHANGELOG` is intended to show developer-impacting changes to the codebase for a particular version.
116 | If every change or commit to the code resulted in an entry, the `CHANGELOG` would become less useful for developers.
117 | The lists below are general guidelines to decide whether a change should have an entry.
118 |
119 | ##### Changes that should not have a `CHANGELOG` entry
120 |
121 | * Documentation updates
122 | * Testing updates
123 | * Code refactoring
124 |
125 | ##### Changes that may have a `CHANGELOG` entry
126 |
127 | * Dependency updates: If the update contains relevant bug fixes or enhancements that affect developers,
128 | those should be called out.
129 |
130 | ##### Changes that should have a `CHANGELOG` entry
131 |
132 | * Major features
133 | * Bug fixes
134 | * Enhancements
135 | * Deprecations
136 | * Breaking changes and removals
137 |
138 | ### License Headers
139 |
140 | All source code files (excluding autogenerated files like `go.mod`, prose, and files excluded in [.copywrite.hcl](../.copywrite.hcl)) must have a license header at the top.
141 |
142 | This can be autogenerated by running `make generate` or running `go generate ./...` in the [/tools](../tools) directory.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/Bug_Report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Something is incorrect or not working as expected.
3 | labels: ["bug"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Thank you for taking the time to fill out this bug report! Please note that this issue tracker is only used for bug reports and feature requests. Other issues will be closed.
9 |
10 | If you have a configuration, workflow, or other question, please go back to the issue chooser and select one of the question links.
11 | - type: textarea
12 | id: versions
13 | attributes:
14 | label: Terraform CLI and Provider Versions
15 | description: What versions of Terraform CLI and the provider?
16 | placeholder: Output of `terraform version` from configuration directory
17 | validations:
18 | required: true
19 | - type: textarea
20 | id: terraform-configuration
21 | attributes:
22 | label: Terraform Configuration
23 | description: Please copy and paste any relevant Terraform configuration. This will be automatically formatted into code, so no need for backticks.
24 | render: terraform
25 | validations:
26 | required: true
27 | - type: textarea
28 | id: expected-behavior
29 | attributes:
30 | label: Expected Behavior
31 | description: What did you expect to happen?
32 | placeholder: Description of what should have happened.
33 | validations:
34 | required: true
35 | - type: textarea
36 | id: actual-behavior
37 | attributes:
38 | label: Actual Behavior
39 | description: What actually happened?
40 | placeholder: Description of what actually happened.
41 | validations:
42 | required: true
43 | - type: textarea
44 | id: reproduction-steps
45 | attributes:
46 | label: Steps to Reproduce
47 | description: List of steps to reproduce the issue.
48 | value: |
49 | 1. `terraform apply`
50 | validations:
51 | required: true
52 | - type: dropdown
53 | id: impact
54 | attributes:
55 | label: How much impact is this issue causing?
56 | description: High represents completely not able to use the provider or unexpected destruction of data/infrastructure. Medium represents unable to upgrade provider version or an issue with potential workaround. Low represents minor provider code, configuration, or documentation issues.
57 | options:
58 | - High
59 | - Medium
60 | - Low
61 | validations:
62 | required: true
63 | - type: input
64 | id: logs
65 | attributes:
66 | label: Logs
67 | description: Please provide a link to a [GitHub Gist](https://gist.github.com) containing TRACE log output. [Terraform Debugging Documentation](https://www.terraform.io/internals/debugging)
68 | placeholder: https://gist.github.com/example/12345678
69 | validations:
70 | required: false
71 | - type: textarea
72 | id: additional-information
73 | attributes:
74 | label: Additional Information
75 | description: Are there any additional details about your environment, workflow, or recent changes that might be relevant? Have you discovered a workaround? Are there links to other related issues?
76 | validations:
77 | required: false
78 | - type: checkboxes
79 | id: terms
80 | attributes:
81 | label: Code of Conduct
82 | description: By submitting this issue, you agree to follow our [Community Guidelines](https://www.hashicorp.com/community-guidelines).
83 | options:
84 | - label: I agree to follow this project's Code of Conduct
85 | required: true
86 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/Feature_Request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Something is missing or could be improved.
3 | labels: ["enhancement"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Thank you for taking the time to fill out this feature request! Please note that this issue tracker is only used for bug reports and feature requests. Other issues will be closed.
9 |
10 | If you have a configuration, workflow, or other question, please go back to the issue chooser and select one of the question links.
11 | - type: textarea
12 | id: versions
13 | attributes:
14 | label: Terraform CLI and Provider Versions
15 | description: What versions of Terraform CLI and the provider?
16 | placeholder: Output of `terraform version` from configuration directory
17 | validations:
18 | required: true
19 | - type: textarea
20 | id: use-case
21 | attributes:
22 | label: Use Cases or Problem Statement
23 | description: What use cases or problems are you trying to solve?
24 | placeholder: Description of use cases or problems.
25 | validations:
26 | required: true
27 | - type: textarea
28 | id: proposal
29 | attributes:
30 | label: Proposal
31 | description: What solutions would you prefer?
32 | placeholder: Description of proposed solutions.
33 | validations:
34 | required: true
35 | - type: dropdown
36 | id: impact
37 | attributes:
38 | label: How much impact is this issue causing?
39 | description: High represents completely not able to use the provider without this. Medium represents unable to solve a specific problem or understand something. Low represents minor provider code, configuration, or documentation issues.
40 | options:
41 | - High
42 | - Medium
43 | - Low
44 | validations:
45 | required: true
46 | - type: textarea
47 | id: additional-information
48 | attributes:
49 | label: Additional Information
50 | description: Are there any additional details about your environment, workflow, or recent changes that might be relevant? Have you discovered a workaround? Are there links to other related issues?
51 | validations:
52 | required: false
53 | - type: checkboxes
54 | id: terms
55 | attributes:
56 | label: Code of Conduct
57 | description: By submitting this issue, you agree to follow our [Community Guidelines](https://www.hashicorp.com/community-guidelines).
58 | options:
59 | - label: I agree to follow this project's Code of Conduct
60 | required: true
61 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Terraform Provider Questions
4 | url: https://discuss.hashicorp.com/c/terraform-providers/31
5 | about: GitHub issues in this repository are only intended for bug reports and feature requests. Other issues will be closed. Please ask and answer questions through the Terraform Provider section of HashiCorp Discuss.
6 | - name: Terraform Language or Workflow Questions
7 | url: https://discuss.hashicorp.com/c/terraform-core
8 | about: Please ask and answer language or workflow related questions through the Terraform Core section of HashiCorp Discuss.
9 |
--------------------------------------------------------------------------------
/.github/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # Support
2 |
3 | * Project [README](../README.md)
4 | * Official [Documentation](https://registry.terraform.io/providers/hashicorp/local/latest/docs)
5 | * Providers [Discuss forums](https://discuss.hashicorp.com/c/terraform-providers/31)
6 | * Terraform [Community](https://www.terraform.io/community.html) page
7 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # See GitHub's docs for more information on this file:
2 | # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates
3 | version: 2
4 | updates:
5 | # Maintain dependencies for Go modules
6 | - package-ecosystem: "gomod"
7 | directory: "/"
8 | schedule:
9 | # Check for updates to Go modules every weekday
10 | interval: "daily"
11 | - package-ecosystem: "gomod"
12 | directory: "/tools"
13 | schedule:
14 | interval: "daily"
15 | - package-ecosystem: "github-actions"
16 | directory: "/"
17 | schedule:
18 | interval: "daily"
19 |
--------------------------------------------------------------------------------
/.github/labeler-issue-triage.yml:
--------------------------------------------------------------------------------
1 | bug:
2 | - 'panic:'
3 | crash:
4 | - 'panic:'
5 |
--------------------------------------------------------------------------------
/.github/labeler-pull-request-triage.yml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - changed-files:
3 | - any-glob-to-any-file: .github/dependabot.yml
4 | - any-glob-to-any-file: go.mod
5 | - any-glob-to-any-file: go.sum
6 | documentation:
7 | - changed-files:
8 | - any-glob-to-any-file: website/**/*
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Related Issue
2 |
3 | Fixes #
4 |
5 | ## Description
6 |
7 | In plain English, describe your approach to addressing the issue linked above. For example, if you made a particular design decision, let us know why you chose this path instead of another solution.
8 |
9 |
10 | ## Rollback Plan
11 |
12 | - [ ] If a change needs to be reverted, we will roll out an update to the code within 7 days.
13 |
14 | ## Changes to Security Controls
15 |
16 | Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.
17 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow builds the product for all supported platforms and uploads the resulting
2 | # binaries as Actions artifacts. The workflow also uploads a build metadata file
3 | # (metadata.json) -- and a Terraform Registry manifest file (terraform-registry-manifest.json).
4 | #
5 | # Reference: https://github.com/hashicorp/terraform-provider-crt-example/blob/main/.github/workflows/README.md
6 |
7 | name: build
8 |
9 | # We default to running this workflow on every push to every branch.
10 | # This provides fast feedback when build issues occur, so they can be
11 | # fixed prior to being merged to the main branch.
12 |
13 | on: [workflow_dispatch, push]
14 |
15 | env:
16 | PKG_NAME: "terraform-provider-cloudinit"
17 |
18 | jobs:
19 | # Detects the Go toolchain version to use for product builds.
20 | #
21 | # The implementation is inspired by envconsul -- https://go.hashi.co/get-go-version-example
22 | get-go-version:
23 | name: "Detect Go toolchain version"
24 | runs-on: ubuntu-latest
25 | outputs:
26 | go-version: ${{ steps.get-go-version.outputs.go-version }}
27 | steps:
28 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
29 | - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
30 | with:
31 | go-version-file: 'go.mod'
32 | - name: Detect Go version
33 | id: get-go-version
34 | run: |
35 | version="$(go list -f {{.GoVersion}} -m)"
36 | echo "go-version=$version" >> "$GITHUB_OUTPUT"
37 |
38 | # Parses the version/VERSION file. Reference: https://github.com/hashicorp/actions-set-product-version/blob/main/README.md
39 | #
40 | # > This action should be implemented in product repo `build.yml` files. The action is intended to grab the version
41 | # > from the version file at the beginning of the build, then passes those versions (along with metadata, where
42 | # > necessary) to any workflow jobs that need version information.
43 | set-product-version:
44 | name: "Parse version file"
45 | runs-on: ubuntu-latest
46 | outputs:
47 | product-version: ${{ steps.set-product-version.outputs.product-version }}
48 | product-base-version: ${{ steps.set-product-version.outputs.base-product-version }}
49 | product-prerelease-version: ${{ steps.set-product-version.outputs.prerelease-product-version }}
50 | product-minor-version: ${{ steps.set-product-version.outputs.minor-product-version }}
51 | steps:
52 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
53 | - name: Set variables
54 | id: set-product-version
55 | uses: hashicorp/actions-set-product-version@v2
56 |
57 | # Creates metadata.json file containing build metadata for consumption by CRT workflows.
58 | #
59 | # Reference: https://github.com/hashicorp/actions-generate-metadata/blob/main/README.md
60 | generate-metadata-file:
61 | needs: set-product-version
62 | runs-on: ubuntu-latest
63 | outputs:
64 | filepath: ${{ steps.generate-metadata-file.outputs.filepath }}
65 | steps:
66 | - name: "Checkout directory"
67 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
68 | - name: Generate metadata file
69 | id: generate-metadata-file
70 | uses: hashicorp/actions-generate-metadata@v1
71 | with:
72 | version: ${{ needs.set-product-version.outputs.product-version }}
73 | product: ${{ env.PKG_NAME }}
74 | repositoryOwner: "hashicorp"
75 | - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
76 | with:
77 | name: metadata.json
78 | path: ${{ steps.generate-metadata-file.outputs.filepath }}
79 |
80 | # Uploads an Actions artifact named terraform-registry-manifest.json.zip.
81 | #
82 | # The artifact contains a single file with a filename that Terraform Registry expects
83 | # (example: terraform-provider-cloudinit_2.3.6-alpha1_manifest.json). The file contents
84 | # are identical to the terraform-registry-manifest.json file in the source repository.
85 | upload-terraform-registry-manifest-artifact:
86 | needs: set-product-version
87 | runs-on: ubuntu-latest
88 | steps:
89 | - name: "Checkout directory"
90 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
91 | with:
92 | path: ${{ env.PKG_NAME }}
93 | - name: "Copy manifest from checkout directory to a file with the desired name"
94 | id: terraform-registry-manifest
95 | run: |
96 | name="${{ env.PKG_NAME }}"
97 | version="${{ needs.set-product-version.outputs.product-version }}"
98 |
99 | source="${name}/terraform-registry-manifest.json"
100 | destination="${name}_${version}_manifest.json"
101 |
102 | cp "$source" "$destination"
103 | echo "filename=$destination" >> "$GITHUB_OUTPUT"
104 | - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
105 | with:
106 | name: terraform-registry-manifest.json
107 | path: ${{ steps.terraform-registry-manifest.outputs.filename }}
108 | if-no-files-found: error
109 |
110 | # Builds the product for all platforms except macOS.
111 | #
112 | # With `reproducible: report`, this job also reports whether the build is reproducible,
113 | # but does not enforce it.
114 | #
115 | # Reference: https://github.com/hashicorp/actions-go-build/blob/main/README.md
116 | build:
117 | needs:
118 | - get-go-version
119 | - set-product-version
120 | runs-on: ubuntu-latest
121 | strategy:
122 | fail-fast: true
123 | matrix:
124 | goos: [freebsd, windows, linux, darwin]
125 | goarch: ["386", "amd64", "arm", "arm64"]
126 | exclude:
127 | - goos: freebsd
128 | goarch: arm64
129 | - goos: windows
130 | goarch: arm64
131 | - goos: windows
132 | goarch: arm
133 | - goos: darwin
134 | goarch: 386
135 | - goos: darwin
136 | goarch: arm
137 |
138 | name: Go ${{ needs.get-go-version.outputs.go-version }} ${{ matrix.goos }} ${{ matrix.goarch }} build
139 | steps:
140 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
141 | - uses: hashicorp/actions-go-build@v1
142 | env:
143 | CGO_ENABLED: 0
144 | BASE_VERSION: ${{ needs.set-product-version.outputs.product-base-version }}
145 | PRERELEASE_VERSION: ${{ needs.set-product-version.outputs.product-prerelease-version}}
146 | METADATA_VERSION: ${{ env.METADATA }}
147 | with:
148 | bin_name: "${{ env.PKG_NAME }}_v${{ needs.set-product-version.outputs.product-version }}_x5"
149 | product_name: ${{ env.PKG_NAME }}
150 | product_version: ${{ needs.set-product-version.outputs.product-version }}
151 | go_version: ${{ needs.get-go-version.outputs.go-version }}
152 | os: ${{ matrix.goos }}
153 | arch: ${{ matrix.goarch }}
154 | reproducible: report
155 | instructions: |
156 | go build \
157 | -o "$BIN_PATH" \
158 | -trimpath \
159 | -buildvcs=false \
160 | -ldflags "-s -w"
161 | cp LICENSE "$TARGET_DIR/LICENSE.txt"
162 |
163 | whats-next:
164 | needs:
165 | - build
166 | - generate-metadata-file
167 | - upload-terraform-registry-manifest-artifact
168 | runs-on: ubuntu-latest
169 | name: "What's next?"
170 | steps:
171 | - name: "Write a helpful summary"
172 | run: |
173 | github_dot_com="${{ github.server_url }}"
174 | owner_with_name="${{ github.repository }}"
175 | ref="${{ github.ref }}"
176 |
177 | echo "### What's next?" >> "$GITHUB_STEP_SUMMARY"
178 | echo "#### For a release branch (see \`.release/ci.hcl\`)" >> $GITHUB_STEP_SUMMARY
179 | echo "After this \`build\` workflow run completes succesfully, you can expect the CRT \`prepare\` workflow to begin momentarily." >> "$GITHUB_STEP_SUMMARY"
180 | echo "To find the \`prepare\` workflow run, [view the checks for this commit]($github_dot_com/$owner_with_name/commits/$ref)" >> "$GITHUB_STEP_SUMMARY"
181 |
--------------------------------------------------------------------------------
/.github/workflows/ci-changie.yml:
--------------------------------------------------------------------------------
1 | # DO NOT EDIT - This GitHub Workflow is managed by automation
2 | # https://github.com/hashicorp/terraform-devex-repos
3 |
4 | # Continuous integration handling for changie
5 | name: ci-changie
6 |
7 | on:
8 | pull_request:
9 | paths:
10 | - .changes/unreleased/*.yaml
11 | - .changie.yaml
12 | - .github/workflows/ci-changie.yml
13 |
14 | permissions:
15 | contents: read
16 |
17 | jobs:
18 | check:
19 | runs-on: ubuntu-latest
20 | steps:
21 | # Ensure terraform-devex-repos is updated on version changes.
22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23 | # Ensure terraform-devex-repos is updated on version changes.
24 | - uses: miniscruff/changie-action@6dcc2533cac0495148ed4046c438487e4dceaa23 # v2.0.0
25 | with:
26 | version: latest
27 | args: batch patch --dry-run
28 |
--------------------------------------------------------------------------------
/.github/workflows/compliance.yml:
--------------------------------------------------------------------------------
1 | name: compliance
2 |
3 | on:
4 | pull_request:
5 |
6 | permissions:
7 | contents: read
8 |
9 | jobs:
10 | # Reference: ENGSRV-059
11 | copywrite:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
15 | - uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 # v1.1.3
16 | - run: copywrite headers --plan
17 | - run: copywrite license --plan
18 |
--------------------------------------------------------------------------------
/.github/workflows/issue-comment-triage.yml:
--------------------------------------------------------------------------------
1 | # DO NOT EDIT - This GitHub Workflow is managed by automation
2 | # https://github.com/hashicorp/terraform-devex-repos
3 | name: Issue Comment Triage
4 |
5 | on:
6 | issue_comment:
7 | types: [created]
8 |
9 | jobs:
10 | issue_comment_triage:
11 | runs-on: ubuntu-latest
12 | env:
13 | # issue_comment events are triggered by comments on issues and pull requests. Checking the
14 | # value of github.event.issue.pull_request tells us whether the issue is an issue or is
15 | # actually a pull request, allowing us to dynamically set the gh subcommand:
16 | # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment-on-issues-only-or-pull-requests-only
17 | COMMAND: ${{ github.event.issue.pull_request && 'pr' || 'issue' }}
18 | GH_TOKEN: ${{ github.token }}
19 | steps:
20 | - name: 'Remove waiting-response on comment'
21 | run: gh ${{ env.COMMAND }} edit ${{ github.event.issue.html_url }} --remove-label waiting-response
22 |
--------------------------------------------------------------------------------
/.github/workflows/issue-opened.yml:
--------------------------------------------------------------------------------
1 | name: Issue Opened Triage
2 |
3 | on:
4 | issues:
5 | types: [opened]
6 |
7 | jobs:
8 | issue_triage:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
12 | - uses: github/issue-labeler@c1b0f9f52a63158c4adc09425e858e87b32e9685 # v3.4
13 | with:
14 | repo-token: "${{ secrets.GITHUB_TOKEN }}"
15 | configuration-path: .github/labeler-issue-triage.yml
16 | enable-versioned-regex: 0
17 |
--------------------------------------------------------------------------------
/.github/workflows/lock.yml:
--------------------------------------------------------------------------------
1 | # DO NOT EDIT - This GitHub Workflow is managed by automation
2 | # https://github.com/hashicorp/terraform-devex-repos
3 | name: 'Lock Threads'
4 |
5 | on:
6 | schedule:
7 | - cron: '9 1 * * *'
8 |
9 | jobs:
10 | lock:
11 | runs-on: ubuntu-latest
12 | steps:
13 | # NOTE: When TSCCR updates the GitHub action version, update the template workflow file to avoid drift:
14 | # https://github.com/hashicorp/terraform-devex-repos/blob/main/modules/repo/workflows/lock.tftpl
15 | - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
16 | with:
17 | github-token: ${{ github.token }}
18 | issue-inactive-days: '30'
19 | issue-lock-reason: resolved
20 | pr-inactive-days: '30'
21 | pr-lock-reason: resolved
22 |
--------------------------------------------------------------------------------
/.github/workflows/pull-request.yml:
--------------------------------------------------------------------------------
1 | name: "Pull Request Triage"
2 |
3 | on: [pull_request_target]
4 |
5 | permissions:
6 | # CodelyTV/pr-size-labeler uses issues URL for labeling
7 | issues: write
8 | pull-requests: write
9 |
10 | jobs:
11 | triage:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
15 | with:
16 | configuration-path: .github/labeler-pull-request-triage.yml
17 | repo-token: "${{ secrets.GITHUB_TOKEN }}"
18 | - uses: CodelyTV/pr-size-labeler@4ec67706cd878fbc1c8db0a5dcd28b6bb412e85a # v1.10.3
19 | with:
20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
21 | xs_label: 'size/XS'
22 | xs_max_size: '30'
23 | s_label: 'size/S'
24 | s_max_size: '60'
25 | m_label: 'size/M'
26 | m_max_size: '150'
27 | l_label: 'size/L'
28 | l_max_size: '300'
29 | xl_label: 'size/XL'
30 | message_if_xl: ''
31 | files_to_ignore: 'go.sum'
32 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on:
4 | pull_request:
5 | branches: [ main ]
6 | paths-ignore:
7 | - 'README.md'
8 | - 'CHANGELOG.md'
9 | - 'website/*'
10 | push:
11 | branches: [ main ]
12 | paths-ignore:
13 | - 'README.md'
14 | - 'CHANGELOG.md'
15 | - 'website/*'
16 |
17 | jobs:
18 |
19 | build:
20 | name: Build
21 | runs-on: ubuntu-latest
22 | timeout-minutes: 5
23 |
24 | steps:
25 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
26 | - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
27 | with:
28 | go-version-file: 'go.mod'
29 |
30 | - name: Run linters
31 | uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
32 | with:
33 | version: latest
34 |
35 | # We need the latest version of Terraform for our documentation generation to use
36 | - name: Set up Terraform
37 | uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
38 | with:
39 | terraform_wrapper: false
40 |
41 | - name: Generate
42 | run: make generate
43 |
44 | - name: Confirm no diff
45 | run: |
46 | git diff --compact-summary --exit-code || \
47 | (echo "*** Unexpected differences after code generation. Run 'make generate' and commit."; exit 1)
48 |
49 | - name: Build
50 | run: make build
51 |
52 | test:
53 | name: 'Acc. Tests (OS: ${{ matrix.os }} / TF: ${{ matrix.terraform }})'
54 | needs: build
55 | runs-on: ${{ matrix.os }}
56 | timeout-minutes: 15
57 |
58 | strategy:
59 | fail-fast: false
60 | matrix:
61 | os:
62 | - macos-latest
63 | - windows-latest
64 | - ubuntu-latest
65 | terraform: ${{ fromJSON(vars.TF_VERSIONS_PROTOCOL_V5) }}
66 |
67 | steps:
68 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
69 | - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
70 | with:
71 | go-version-file: 'go.mod'
72 |
73 | - name: Setup Terraform ${{ matrix.terraform }}
74 | uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
75 | with:
76 | terraform_version: ${{ matrix.terraform }}
77 | terraform_wrapper: false
78 |
79 | - name: Run acceptance test
80 | run: make testacc
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.dll
2 | *.exe
3 | .DS_Store
4 | example.tf
5 | terraform.tfplan
6 | terraform.tfstate
7 | bin/
8 | modules-dev/
9 | /pkg/
10 | website/.vagrant
11 | website/.bundle
12 | website/build
13 | website/node_modules
14 | .vagrant/
15 | *.backup
16 | ./*.tfstate
17 | .terraform/
18 | *.log
19 | *.bak
20 | *~
21 | .*.swp
22 | .idea
23 | *.iml
24 | *.test
25 | *.iml
26 |
27 | website/vendor
28 |
29 | # Test exclusions
30 | !command/test-fixtures/**/*.tfstate
31 | !command/test-fixtures/**/.terraform/
32 |
33 | # Keep windows files with windows line endings
34 | *.winfile eol=crlf
35 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | linters:
3 | default: none
4 | enable:
5 | - copyloopvar
6 | - durationcheck
7 | - errcheck
8 | - forcetypeassert
9 | - godot
10 | - govet
11 | - ineffassign
12 | - makezero
13 | - misspell
14 | - nilerr
15 | - predeclared
16 | - staticcheck
17 | - unconvert
18 | - unparam
19 | - unused
20 | - usetesting
21 | exclusions:
22 | generated: lax
23 | presets:
24 | - comments
25 | - common-false-positives
26 | - legacy
27 | - std-error-handling
28 | paths:
29 | - third_party$
30 | - builtin$
31 | - examples$
32 | settings:
33 | staticcheck:
34 | checks:
35 | - all
36 | - '-QF1012' # "Use fmt.Fprintf(...) instead of Write" -- https://staticcheck.io/docs/checks#QF1012
37 |
38 | issues:
39 | max-issues-per-linter: 0
40 | max-same-issues: 0
41 | formatters:
42 | enable:
43 | - gofmt
44 | exclusions:
45 | generated: lax
46 | paths:
47 | - third_party$
48 | - builtin$
49 | - examples$
50 |
--------------------------------------------------------------------------------
/.release/ci.hcl:
--------------------------------------------------------------------------------
1 | # Reference: https://github.com/hashicorp/crt-core-helloworld/blob/main/.release/ci.hcl (private repository)
2 | #
3 | # One way to validate, with a local build of the orchestrator (an internal repo):
4 | #
5 | # $ GITHUB_TOKEN="not-used" orchestrator parse config -use-v2 -local-config=.release/ci.hcl
6 |
7 | schema = "2"
8 |
9 | project "terraform-provider-cloudinit" {
10 | // team is currently unused and has no meaning
11 | // but is required to be non-empty by CRT orchestator
12 | team = "_UNUSED_"
13 |
14 | slack {
15 | notification_channel = "C02BASDVCDT" // #feed-terraform-sdk
16 | }
17 |
18 | github {
19 | organization = "hashicorp"
20 | repository = "terraform-provider-cloudinit"
21 | release_branches = ["main", "release/**"]
22 | }
23 | }
24 |
25 | event "merge" {
26 | }
27 |
28 | event "build" {
29 | action "build" {
30 | depends = ["merge"]
31 |
32 | organization = "hashicorp"
33 | repository = "terraform-provider-cloudinit"
34 | workflow = "build"
35 | }
36 | }
37 |
38 | event "prepare" {
39 | # `prepare` is the Common Release Tooling (CRT) artifact processing workflow.
40 | # It prepares artifacts for potential promotion to staging and production.
41 | # For example, it scans and signs artifacts.
42 |
43 | depends = ["build"]
44 |
45 | action "prepare" {
46 | organization = "hashicorp"
47 | repository = "crt-workflows-common"
48 | workflow = "prepare"
49 | depends = ["build"]
50 | }
51 |
52 | notification {
53 | on = "fail"
54 | }
55 | }
56 |
57 | event "trigger-staging" {
58 | }
59 |
60 | event "promote-staging" {
61 | action "promote-staging" {
62 | organization = "hashicorp"
63 | repository = "crt-workflows-common"
64 | workflow = "promote-staging"
65 | depends = null
66 | config = "release-metadata.hcl"
67 | }
68 |
69 | depends = ["trigger-staging"]
70 |
71 | notification {
72 | on = "always"
73 | }
74 | }
75 |
76 | event "trigger-production" {
77 | }
78 |
79 | event "promote-production" {
80 | action "promote-production" {
81 | organization = "hashicorp"
82 | repository = "crt-workflows-common"
83 | workflow = "promote-production"
84 | depends = null
85 | config = ""
86 | }
87 |
88 | depends = ["trigger-production"]
89 |
90 | notification {
91 | on = "always"
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/.release/release-metadata.hcl:
--------------------------------------------------------------------------------
1 | url_source_repository = "https://github.com/hashicorp/terraform-provider-cloudinit"
2 | url_project_website = "https://registry.terraform.io/providers/hashicorp/cloudinit"
3 | url_license = "https://github.com/hashicorp/terraform-provider-cloudinit/blob/main/LICENSE"
4 | url_release_notes = "https://github.com/hashicorp/terraform-provider-cloudinit/blob/main/CHANGELOG.md"
5 |
--------------------------------------------------------------------------------
/.release/security-scan.hcl:
--------------------------------------------------------------------------------
1 | # Reference: https://github.com/hashicorp/security-scanner/blob/main/CONFIG.md#binary (private repository)
2 |
3 | binary {
4 | secrets {
5 | all = true
6 | }
7 | go_modules = true
8 | osv = true
9 | oss_index = false
10 | nvd = false
11 | }
12 |
--------------------------------------------------------------------------------
/.release/terraform-provider-cloudinit-artifacts.hcl:
--------------------------------------------------------------------------------
1 | schema = 1
2 | artifacts {
3 | zip = [
4 | "terraform-provider-cloudinit_${version}_darwin_amd64.zip",
5 | "terraform-provider-cloudinit_${version}_darwin_arm64.zip",
6 | "terraform-provider-cloudinit_${version}_freebsd_386.zip",
7 | "terraform-provider-cloudinit_${version}_freebsd_amd64.zip",
8 | "terraform-provider-cloudinit_${version}_freebsd_arm.zip",
9 | "terraform-provider-cloudinit_${version}_linux_386.zip",
10 | "terraform-provider-cloudinit_${version}_linux_amd64.zip",
11 | "terraform-provider-cloudinit_${version}_linux_arm.zip",
12 | "terraform-provider-cloudinit_${version}_linux_arm64.zip",
13 | "terraform-provider-cloudinit_${version}_windows_386.zip",
14 | "terraform-provider-cloudinit_${version}_windows_amd64.zip",
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.3.7 (April 21, 2025)
2 |
3 | NOTES:
4 |
5 | * Update dependencies ([#339](https://github.com/hashicorp/terraform-provider-cloudinit/issues/339))
6 |
7 | ## 2.3.7-alpha1 (March 04, 2025)
8 |
9 | NOTES:
10 |
11 | * all: This release is being used to test new build and release actions.
12 |
13 | ## 2.3.6 (February 27, 2025)
14 |
15 | NOTES:
16 |
17 | * all: This release contains no functionality changes. It is being used to fix release metadata in the registry from the previous alpha1 release. ([#318](https://github.com/hashicorp/terraform-provider-cloudinit/issues/318))
18 |
19 | ## 2.3.6-alpha1 (December 05, 2024)
20 |
21 | NOTES:
22 |
23 | * all: This release contains no functionality changes. It is released using new build and release Actions. ([#293](https://github.com/hashicorp/terraform-provider-cloudinit/issues/293))
24 |
25 | ## 2.3.5 (September 10, 2024)
26 |
27 | NOTES:
28 |
29 | * all: This release introduces no functional changes. It does however include dependency updates which address upstream CVEs. ([#263](https://github.com/hashicorp/terraform-provider-cloudinit/issues/263))
30 |
31 | ## 2.3.4 (April 22, 2024)
32 |
33 | NOTES:
34 |
35 | * all: This release contains no functionality changes, only the inclusion of the LICENSE file in the release archives ([#228](https://github.com/hashicorp/terraform-provider-cloudinit/issues/228))
36 |
37 | ## 2.3.3 (November 29, 2023)
38 |
39 | NOTES:
40 |
41 | * This release introduces no functional changes. It does however include dependency updates which address upstream CVEs. ([#186](https://github.com/hashicorp/terraform-provider-cloudinit/issues/186))
42 |
43 | ## 2.3.2 (February 23, 2023)
44 |
45 | BUG FIXES:
46 |
47 | * cloudinit_config: Remove length validation to allow empty content string in part blocks ([#105](https://github.com/hashicorp/terraform-provider-cloudinit/issues/105))
48 |
49 | ## 2.3.1 (February 22, 2023)
50 |
51 | BUG FIXES:
52 |
53 | * cloudinit_config: Fixed handling of unknown values in `part` blocks ([#103](https://github.com/hashicorp/terraform-provider-cloudinit/issues/103))
54 |
55 | ## 2.3.0 (February 22, 2023)
56 |
57 | NOTES:
58 |
59 | * provider: Rewritten to use the [`terraform-plugin-framework`](https://www.terraform.io/plugin/framework) ([#96](https://github.com/hashicorp/terraform-provider-cloudinit/issues/96))
60 |
61 | ## 2.2.0 (February 19, 2021)
62 |
63 | Binary releases of this provider will now include the darwin-arm64 platform. This version contains no further changes.
64 |
65 | ## 2.1.0 (November 26, 2020)
66 |
67 | NEW FEATURES:
68 |
69 | * MIMEBOUNDARY can now be customised with `boundary` ([#7](https://github.com/hashicorp/terraform-provider-cloudinit/issues/7)).
70 |
71 | ## 2.0.0 (October 12, 2020)
72 |
73 | Binary releases of this provider will now include the linux-arm64 platform.
74 |
75 | BREAKING CHANGES:
76 |
77 | * Upgrade to version 2 of the Terraform Plugin SDK, which drops support for Terraform 0.11. This provider will continue to work as expected for users of Terraform 0.11, which will not download the new version. ([#3](https://github.com/hashicorp/terraform-provider-cloudinit/issues/3))
78 |
79 | ## 1.0.0 (April 14, 2020)
80 |
81 | Initial release. This provider exposes one resource, cloudinit_config, which is identical to the template_cloudinit_config resource in terraform-provider-template.
82 |
--------------------------------------------------------------------------------
/DESIGN.md:
--------------------------------------------------------------------------------
1 | # cloud-init Provider Design
2 |
3 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. The cloud-init provider offers functionality to render a MIME multi-part file for use with cloud-init. Using a MIME multi-part file, the user can specify more than one type of user data for cloud-init to consume. If you only have one type of user data, you can leverage the built-in [`templatefile`](https://www.terraform.io/docs/configuration/functions/templatefile.html) function and a static file (like `.yml`).
4 |
5 | Below we have a collection of _Goals_ and _Patterns_: they represent the guiding principles applied during the
6 | development of this provider. Some are in place, others are ongoing processes, others are still just inspirational.
7 |
8 | ## Goals
9 |
10 | * [_Stability over features_](.github/CONTRIBUTING.md)
11 | * Provide a managed resource and data source to generate a cloud-init MIME multi-part file
12 | * This multi-part file can include multiple user data formats, such as **[Cloud config](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#cloud-config-data)** or **[Shell scripts](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#user-data-script)**
13 | * See the official [cloud-init](https://cloudinit.readthedocs.io/en/latest/explanation/index.html) documentation for more information on user data formats and cloud provider specific documentation
14 |
15 | ## Patterns
16 |
17 | Specific to this provider:
18 |
19 | * The managed resource and data source use the same underlying code to generate the MIME multi-part file.
20 |
21 | General to development:
22 |
23 | * **Avoid repetition**: the entities managed can sometimes require similar pieces of logic and/or schema to be realised.
24 | When this happens it's important to keep the code shared in communal sections, so to avoid having to modify code in
25 | multiple places when they start changing.
26 | * **Test expectations as well as bugs**: While it's typical to write tests to exercise a new functionality, it's key to
27 | also provide tests for issues that get identified and fixed, so to prove resolution as well as avoid regression.
28 | * **Automate boring tasks**: Processes that are manual, repetitive and can be automated, should be. In addition to be a
29 | time-saving practice, this ensures consistency and reduces human error (ex. static code analysis).
30 | * **Semantic versioning**: Adhering to HashiCorp's own
31 | [Versioning Specification](https://www.terraform.io/plugin/sdkv2/best-practices/versioning#versioning-specification)
32 | ensures we provide a consistent practitioner experience, and a clear process to deprecation and decommission.
--------------------------------------------------------------------------------
/GNUmakefile:
--------------------------------------------------------------------------------
1 | default: build
2 |
3 | build:
4 | go build -v ./...
5 |
6 | install: build
7 | go install -v ./...
8 |
9 | # See https://golangci-lint.run/
10 | lint:
11 | golangci-lint run
12 |
13 | # Generate docs and copywrite headers
14 | generate:
15 | cd tools; go generate ./...
16 |
17 | fmt:
18 | gofmt -s -w -e .
19 |
20 | test:
21 | go test -v -cover -timeout=120s -parallel=4 ./...
22 |
23 | testacc:
24 | TF_ACC=1 go test -v -cover -timeout 120m ./...
25 |
26 | .PHONY: build install lint generate fmt test testacc
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019 HashiCorp, Inc.
2 |
3 | Mozilla Public License Version 2.0
4 | ==================================
5 |
6 | 1. Definitions
7 | --------------
8 |
9 | 1.1. "Contributor"
10 | means each individual or legal entity that creates, contributes to
11 | the creation of, or owns Covered Software.
12 |
13 | 1.2. "Contributor Version"
14 | means the combination of the Contributions of others (if any) used
15 | by a Contributor and that particular Contributor's Contribution.
16 |
17 | 1.3. "Contribution"
18 | means Covered Software of a particular Contributor.
19 |
20 | 1.4. "Covered Software"
21 | means Source Code Form to which the initial Contributor has attached
22 | the notice in Exhibit A, the Executable Form of such Source Code
23 | Form, and Modifications of such Source Code Form, in each case
24 | including portions thereof.
25 |
26 | 1.5. "Incompatible With Secondary Licenses"
27 | means
28 |
29 | (a) that the initial Contributor has attached the notice described
30 | in Exhibit B to the Covered Software; or
31 |
32 | (b) that the Covered Software was made available under the terms of
33 | version 1.1 or earlier of the License, but not also under the
34 | terms of a Secondary License.
35 |
36 | 1.6. "Executable Form"
37 | means any form of the work other than Source Code Form.
38 |
39 | 1.7. "Larger Work"
40 | means a work that combines Covered Software with other material, in
41 | a separate file or files, that is not Covered Software.
42 |
43 | 1.8. "License"
44 | means this document.
45 |
46 | 1.9. "Licensable"
47 | means having the right to grant, to the maximum extent possible,
48 | whether at the time of the initial grant or subsequently, any and
49 | all of the rights conveyed by this License.
50 |
51 | 1.10. "Modifications"
52 | means any of the following:
53 |
54 | (a) any file in Source Code Form that results from an addition to,
55 | deletion from, or modification of the contents of Covered
56 | Software; or
57 |
58 | (b) any new file in Source Code Form that contains any Covered
59 | Software.
60 |
61 | 1.11. "Patent Claims" of a Contributor
62 | means any patent claim(s), including without limitation, method,
63 | process, and apparatus claims, in any patent Licensable by such
64 | Contributor that would be infringed, but for the grant of the
65 | License, by the making, using, selling, offering for sale, having
66 | made, import, or transfer of either its Contributions or its
67 | Contributor Version.
68 |
69 | 1.12. "Secondary License"
70 | means either the GNU General Public License, Version 2.0, the GNU
71 | Lesser General Public License, Version 2.1, the GNU Affero General
72 | Public License, Version 3.0, or any later versions of those
73 | licenses.
74 |
75 | 1.13. "Source Code Form"
76 | means the form of the work preferred for making modifications.
77 |
78 | 1.14. "You" (or "Your")
79 | means an individual or a legal entity exercising rights under this
80 | License. For legal entities, "You" includes any entity that
81 | controls, is controlled by, or is under common control with You. For
82 | purposes of this definition, "control" means (a) the power, direct
83 | or indirect, to cause the direction or management of such entity,
84 | whether by contract or otherwise, or (b) ownership of more than
85 | fifty percent (50%) of the outstanding shares or beneficial
86 | ownership of such entity.
87 |
88 | 2. License Grants and Conditions
89 | --------------------------------
90 |
91 | 2.1. Grants
92 |
93 | Each Contributor hereby grants You a world-wide, royalty-free,
94 | non-exclusive license:
95 |
96 | (a) under intellectual property rights (other than patent or trademark)
97 | Licensable by such Contributor to use, reproduce, make available,
98 | modify, display, perform, distribute, and otherwise exploit its
99 | Contributions, either on an unmodified basis, with Modifications, or
100 | as part of a Larger Work; and
101 |
102 | (b) under Patent Claims of such Contributor to make, use, sell, offer
103 | for sale, have made, import, and otherwise transfer either its
104 | Contributions or its Contributor Version.
105 |
106 | 2.2. Effective Date
107 |
108 | The licenses granted in Section 2.1 with respect to any Contribution
109 | become effective for each Contribution on the date the Contributor first
110 | distributes such Contribution.
111 |
112 | 2.3. Limitations on Grant Scope
113 |
114 | The licenses granted in this Section 2 are the only rights granted under
115 | this License. No additional rights or licenses will be implied from the
116 | distribution or licensing of Covered Software under this License.
117 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
118 | Contributor:
119 |
120 | (a) for any code that a Contributor has removed from Covered Software;
121 | or
122 |
123 | (b) for infringements caused by: (i) Your and any other third party's
124 | modifications of Covered Software, or (ii) the combination of its
125 | Contributions with other software (except as part of its Contributor
126 | Version); or
127 |
128 | (c) under Patent Claims infringed by Covered Software in the absence of
129 | its Contributions.
130 |
131 | This License does not grant any rights in the trademarks, service marks,
132 | or logos of any Contributor (except as may be necessary to comply with
133 | the notice requirements in Section 3.4).
134 |
135 | 2.4. Subsequent Licenses
136 |
137 | No Contributor makes additional grants as a result of Your choice to
138 | distribute the Covered Software under a subsequent version of this
139 | License (see Section 10.2) or under the terms of a Secondary License (if
140 | permitted under the terms of Section 3.3).
141 |
142 | 2.5. Representation
143 |
144 | Each Contributor represents that the Contributor believes its
145 | Contributions are its original creation(s) or it has sufficient rights
146 | to grant the rights to its Contributions conveyed by this License.
147 |
148 | 2.6. Fair Use
149 |
150 | This License is not intended to limit any rights You have under
151 | applicable copyright doctrines of fair use, fair dealing, or other
152 | equivalents.
153 |
154 | 2.7. Conditions
155 |
156 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
157 | in Section 2.1.
158 |
159 | 3. Responsibilities
160 | -------------------
161 |
162 | 3.1. Distribution of Source Form
163 |
164 | All distribution of Covered Software in Source Code Form, including any
165 | Modifications that You create or to which You contribute, must be under
166 | the terms of this License. You must inform recipients that the Source
167 | Code Form of the Covered Software is governed by the terms of this
168 | License, and how they can obtain a copy of this License. You may not
169 | attempt to alter or restrict the recipients' rights in the Source Code
170 | Form.
171 |
172 | 3.2. Distribution of Executable Form
173 |
174 | If You distribute Covered Software in Executable Form then:
175 |
176 | (a) such Covered Software must also be made available in Source Code
177 | Form, as described in Section 3.1, and You must inform recipients of
178 | the Executable Form how they can obtain a copy of such Source Code
179 | Form by reasonable means in a timely manner, at a charge no more
180 | than the cost of distribution to the recipient; and
181 |
182 | (b) You may distribute such Executable Form under the terms of this
183 | License, or sublicense it under different terms, provided that the
184 | license for the Executable Form does not attempt to limit or alter
185 | the recipients' rights in the Source Code Form under this License.
186 |
187 | 3.3. Distribution of a Larger Work
188 |
189 | You may create and distribute a Larger Work under terms of Your choice,
190 | provided that You also comply with the requirements of this License for
191 | the Covered Software. If the Larger Work is a combination of Covered
192 | Software with a work governed by one or more Secondary Licenses, and the
193 | Covered Software is not Incompatible With Secondary Licenses, this
194 | License permits You to additionally distribute such Covered Software
195 | under the terms of such Secondary License(s), so that the recipient of
196 | the Larger Work may, at their option, further distribute the Covered
197 | Software under the terms of either this License or such Secondary
198 | License(s).
199 |
200 | 3.4. Notices
201 |
202 | You may not remove or alter the substance of any license notices
203 | (including copyright notices, patent notices, disclaimers of warranty,
204 | or limitations of liability) contained within the Source Code Form of
205 | the Covered Software, except that You may alter any license notices to
206 | the extent required to remedy known factual inaccuracies.
207 |
208 | 3.5. Application of Additional Terms
209 |
210 | You may choose to offer, and to charge a fee for, warranty, support,
211 | indemnity or liability obligations to one or more recipients of Covered
212 | Software. However, You may do so only on Your own behalf, and not on
213 | behalf of any Contributor. You must make it absolutely clear that any
214 | such warranty, support, indemnity, or liability obligation is offered by
215 | You alone, and You hereby agree to indemnify every Contributor for any
216 | liability incurred by such Contributor as a result of warranty, support,
217 | indemnity or liability terms You offer. You may include additional
218 | disclaimers of warranty and limitations of liability specific to any
219 | jurisdiction.
220 |
221 | 4. Inability to Comply Due to Statute or Regulation
222 | ---------------------------------------------------
223 |
224 | If it is impossible for You to comply with any of the terms of this
225 | License with respect to some or all of the Covered Software due to
226 | statute, judicial order, or regulation then You must: (a) comply with
227 | the terms of this License to the maximum extent possible; and (b)
228 | describe the limitations and the code they affect. Such description must
229 | be placed in a text file included with all distributions of the Covered
230 | Software under this License. Except to the extent prohibited by statute
231 | or regulation, such description must be sufficiently detailed for a
232 | recipient of ordinary skill to be able to understand it.
233 |
234 | 5. Termination
235 | --------------
236 |
237 | 5.1. The rights granted under this License will terminate automatically
238 | if You fail to comply with any of its terms. However, if You become
239 | compliant, then the rights granted under this License from a particular
240 | Contributor are reinstated (a) provisionally, unless and until such
241 | Contributor explicitly and finally terminates Your grants, and (b) on an
242 | ongoing basis, if such Contributor fails to notify You of the
243 | non-compliance by some reasonable means prior to 60 days after You have
244 | come back into compliance. Moreover, Your grants from a particular
245 | Contributor are reinstated on an ongoing basis if such Contributor
246 | notifies You of the non-compliance by some reasonable means, this is the
247 | first time You have received notice of non-compliance with this License
248 | from such Contributor, and You become compliant prior to 30 days after
249 | Your receipt of the notice.
250 |
251 | 5.2. If You initiate litigation against any entity by asserting a patent
252 | infringement claim (excluding declaratory judgment actions,
253 | counter-claims, and cross-claims) alleging that a Contributor Version
254 | directly or indirectly infringes any patent, then the rights granted to
255 | You by any and all Contributors for the Covered Software under Section
256 | 2.1 of this License shall terminate.
257 |
258 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
259 | end user license agreements (excluding distributors and resellers) which
260 | have been validly granted by You or Your distributors under this License
261 | prior to termination shall survive termination.
262 |
263 | ************************************************************************
264 | * *
265 | * 6. Disclaimer of Warranty *
266 | * ------------------------- *
267 | * *
268 | * Covered Software is provided under this License on an "as is" *
269 | * basis, without warranty of any kind, either expressed, implied, or *
270 | * statutory, including, without limitation, warranties that the *
271 | * Covered Software is free of defects, merchantable, fit for a *
272 | * particular purpose or non-infringing. The entire risk as to the *
273 | * quality and performance of the Covered Software is with You. *
274 | * Should any Covered Software prove defective in any respect, You *
275 | * (not any Contributor) assume the cost of any necessary servicing, *
276 | * repair, or correction. This disclaimer of warranty constitutes an *
277 | * essential part of this License. No use of any Covered Software is *
278 | * authorized under this License except under this disclaimer. *
279 | * *
280 | ************************************************************************
281 |
282 | ************************************************************************
283 | * *
284 | * 7. Limitation of Liability *
285 | * -------------------------- *
286 | * *
287 | * Under no circumstances and under no legal theory, whether tort *
288 | * (including negligence), contract, or otherwise, shall any *
289 | * Contributor, or anyone who distributes Covered Software as *
290 | * permitted above, be liable to You for any direct, indirect, *
291 | * special, incidental, or consequential damages of any character *
292 | * including, without limitation, damages for lost profits, loss of *
293 | * goodwill, work stoppage, computer failure or malfunction, or any *
294 | * and all other commercial damages or losses, even if such party *
295 | * shall have been informed of the possibility of such damages. This *
296 | * limitation of liability shall not apply to liability for death or *
297 | * personal injury resulting from such party's negligence to the *
298 | * extent applicable law prohibits such limitation. Some *
299 | * jurisdictions do not allow the exclusion or limitation of *
300 | * incidental or consequential damages, so this exclusion and *
301 | * limitation may not apply to You. *
302 | * *
303 | ************************************************************************
304 |
305 | 8. Litigation
306 | -------------
307 |
308 | Any litigation relating to this License may be brought only in the
309 | courts of a jurisdiction where the defendant maintains its principal
310 | place of business and such litigation shall be governed by laws of that
311 | jurisdiction, without reference to its conflict-of-law provisions.
312 | Nothing in this Section shall prevent a party's ability to bring
313 | cross-claims or counter-claims.
314 |
315 | 9. Miscellaneous
316 | ----------------
317 |
318 | This License represents the complete agreement concerning the subject
319 | matter hereof. If any provision of this License is held to be
320 | unenforceable, such provision shall be reformed only to the extent
321 | necessary to make it enforceable. Any law or regulation which provides
322 | that the language of a contract shall be construed against the drafter
323 | shall not be used to construe this License against a Contributor.
324 |
325 | 10. Versions of the License
326 | ---------------------------
327 |
328 | 10.1. New Versions
329 |
330 | Mozilla Foundation is the license steward. Except as provided in Section
331 | 10.3, no one other than the license steward has the right to modify or
332 | publish new versions of this License. Each version will be given a
333 | distinguishing version number.
334 |
335 | 10.2. Effect of New Versions
336 |
337 | You may distribute the Covered Software under the terms of the version
338 | of the License under which You originally received the Covered Software,
339 | or under the terms of any subsequent version published by the license
340 | steward.
341 |
342 | 10.3. Modified Versions
343 |
344 | If you create software not governed by this License, and you want to
345 | create a new license for such software, you may create and use a
346 | modified version of this License if you rename the license and remove
347 | any references to the name of the license steward (except to note that
348 | such modified license differs from this License).
349 |
350 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
351 | Licenses
352 |
353 | If You choose to distribute Source Code Form that is Incompatible With
354 | Secondary Licenses under the terms of this version of the License, the
355 | notice described in Exhibit B of this License must be attached.
356 |
357 | Exhibit A - Source Code Form License Notice
358 | -------------------------------------------
359 |
360 | This Source Code Form is subject to the terms of the Mozilla Public
361 | License, v. 2.0. If a copy of the MPL was not distributed with this
362 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
363 |
364 | If it is not possible or desirable to put the notice in a particular
365 | file, then You may include the notice in a location (such as a LICENSE
366 | file in a relevant directory) where a recipient would be likely to look
367 | for such a notice.
368 |
369 | You may add additional accurate notices of copyright ownership.
370 |
371 | Exhibit B - "Incompatible With Secondary Licenses" Notice
372 | ---------------------------------------------------------
373 |
374 | This Source Code Form is "Incompatible With Secondary Licenses", as
375 | defined by the Mozilla Public License, v. 2.0.
376 |
--------------------------------------------------------------------------------
/META.d/_summary.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | schema: 1.1
3 |
4 | partition: tf-ecosystem
5 |
6 | summary:
7 | owner: team-tf-core-plugins
8 | description: |
9 | Utility provider that exposes the cloudinit_config data source which renders a multipart MIME configuration for use with cloud-init (previously available as the template_cloudinit_config resource in the template provider)
10 | visibility: public
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Terraform Provider: cloud-init
2 |
3 | The cloud-init provider supports rendering [cloud-init](https://cloudinit.readthedocs.io) configurations in a [MIME multi-part file](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive).
4 |
5 | > _This provider is intended to replace the [template provider](https://www.terraform.io/docs/providers/template/). General templating can now be achieved through the [`templatefile`](https://www.terraform.io/docs/configuration/functions/templatefile.html) function, without creating a separate data resource._
6 | > _This provider exposes the `cloudinit_config` data source and resource, previously available as the [`template_cloudinit_config`](https://www.terraform.io/docs/providers/template/d/cloudinit_config.html) in the template provider._
7 |
8 | ## Documentation, questions and discussions
9 |
10 | Official documentation on how to use this provider can be found on the
11 | [Terraform Registry](https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs).
12 | In case of specific questions or discussions, please use the
13 | HashiCorp [Terraform Providers Discuss forums](https://discuss.hashicorp.com/c/terraform-providers/31),
14 | in accordance with HashiCorp [Community Guidelines](https://www.hashicorp.com/community-guidelines).
15 |
16 | We also provide:
17 |
18 | * [Support](.github/SUPPORT.md) page for help when using the provider
19 | * [Contributing](.github/CONTRIBUTING.md) guidelines in case you want to help this project
20 | * [Design](DESIGN.md) documentation to understand the scope and maintenance decisions
21 |
22 | The remainder of this document will focus on the development aspects of the provider.
23 |
24 |
25 | ## Requirements
26 |
27 | * [Terraform](https://www.terraform.io/downloads)
28 | * [Go](https://go.dev/doc/install) (1.23)
29 | * [GNU Make](https://www.gnu.org/software/make/)
30 | * [golangci-lint](https://golangci-lint.run/usage/install/#local-installation) (optional)
31 |
32 | ## Development
33 |
34 | ### Building
35 |
36 | 1. `git clone` this repository and `cd` into its directory
37 | 2. `make` will trigger the Golang build
38 |
39 | The provided `GNUmakefile` defines additional commands generally useful during development,
40 | like for running tests, generating documentation, code formatting and linting.
41 | Taking a look at it's content is recommended.
42 |
43 | ### Testing
44 |
45 | In order to test the provider, you can run
46 |
47 | * `make test` to run provider tests
48 | * `make testacc` to run provider acceptance tests
49 |
50 | It's important to note that acceptance tests (`testacc`) will actually spawn
51 | `terraform` and the provider. Read more about they work on the
52 | [official page](https://www.terraform.io/plugin/sdkv2/testing/acceptance-tests).
53 |
54 | ### Generating documentation
55 |
56 | This provider uses [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/)
57 | to generate documentation and store it in the `docs/` directory.
58 | Once a release is cut, the Terraform Registry will download the documentation from `docs/`
59 | and associate it with the release version. Read more about how this works on the
60 | [official page](https://www.terraform.io/registry/providers/docs).
61 |
62 | Use `make generate` to ensure the documentation is regenerated with any changes.
63 |
64 | ### Using a development build
65 |
66 | If [running tests and acceptance tests](#testing) isn't enough, it's possible to set up a local terraform configuration
67 | to use a development builds of the provider. This can be achieved by leveraging the Terraform CLI
68 | [configuration file development overrides](https://www.terraform.io/cli/config/config-file#development-overrides-for-provider-developers).
69 |
70 | First, use `make install` to place a fresh development build of the provider in your
71 | [`${GOBIN}`](https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies)
72 | (defaults to `${GOPATH}/bin` or `${HOME}/go/bin` if `${GOPATH}` is not set). Repeat
73 | this every time you make changes to the provider locally.
74 |
75 | Then, setup your environment following [these instructions](https://www.terraform.io/plugin/debugging#terraform-cli-development-overrides)
76 | to make your local terraform use your local build.
77 |
78 | ### Testing GitHub Actions
79 |
80 | This project uses [GitHub Actions](https://docs.github.com/en/actions/automating-builds-and-tests) to realize its CI.
81 |
82 | Sometimes it might be helpful to locally reproduce the behaviour of those actions,
83 | and for this we use [act](https://github.com/nektos/act). Once installed, you can _simulate_ the actions executed
84 | when opening a PR with:
85 |
86 | ```shell
87 | # List of workflows for the 'pull_request' action
88 | $ act -l pull_request
89 |
90 | # Execute the workflows associated with the `pull_request' action
91 | $ act pull_request
92 | ```
93 |
94 | ## Releasing
95 |
96 | The releasable builds are generated from the [build GH workflow](./.github/workflows/build.yml) and the release/promotion process
97 | is completed via internal HashiCorp deployment tooling. Prior to release, the changelog should be updated in `main` with
98 | the changie tool, example:
99 |
100 | ```sh
101 | changie batch 2.3.7 && changie merge
102 | ```
103 |
104 | ## License
105 |
106 | [Mozilla Public License v2.0](./LICENSE)
107 |
--------------------------------------------------------------------------------
/docs/cdktf/python/data-sources/config.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit_config Data Source - terraform-provider-cloudinit"
3 | description: |-
4 | Renders a multi-part MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as user_data for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see User-Data Formats https://cloudinit.readthedocs.io/en/latest/explanation/format.html in the cloud-init manual.
6 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
7 | ---
8 |
9 |
10 |
11 | # cloudinit_config (Data Source)
12 |
13 | Renders a [multi-part MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
14 |
15 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as `user_data` for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see [User-Data Formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) in the cloud-init manual.
16 |
17 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
18 |
19 | ## Example Usage
20 |
21 | ### Config
22 | ```python
23 | # DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
24 | from constructs import Construct
25 | from cdktf import Fn, Token, TerraformStack
26 | #
27 | # Provider bindings are generated by running `cdktf get`.
28 | # See https://cdk.tf/provider-generation for more details.
29 | #
30 | from imports.cloudinit.data_cloudinit_config import DataCloudinitConfig
31 | class MyConvertedCode(TerraformStack):
32 | def __init__(self, scope, name):
33 | super().__init__(scope, name)
34 | DataCloudinitConfig(self, "foobar",
35 | base64_encode=False,
36 | gzip=False,
37 | part=[DataCloudinitConfigPart(
38 | content=Token.as_string(Fn.file("${path.module}/hello-script.sh")),
39 | content_type="text/x-shellscript",
40 | filename="hello-script.sh"
41 | ), DataCloudinitConfigPart(
42 | content=Token.as_string(Fn.file("${path.module}/cloud-config.yaml")),
43 | content_type="text/cloud-config",
44 | filename="cloud-config.yaml"
45 | )
46 | ]
47 | )
48 | ```
49 |
50 | ### hello-script.sh
51 | ```shell
52 | #!/bin/sh
53 | echo "Hello World! I'm starting up now at $(date -R)!"
54 | ```
55 |
56 | ### cloud-config.yaml
57 | ```yaml
58 | #cloud-config
59 | # See documentation for more configuration examples
60 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html
61 |
62 | # Install arbitrary packages
63 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#install-arbitrary-packages
64 | packages:
65 | - python
66 | # Run commands on first boot
67 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#run-commands-on-first-boot
68 | runcmd:
69 | - [ ls, -l, / ]
70 | - [ sh, -xc, "echo $(date) ': hello world!'" ]
71 | - [ sh, -c, echo "=========hello world=========" ]
72 | - ls -l /root
73 | ```
74 |
75 |
76 |
77 | ## Schema
78 |
79 | ### Required
80 |
81 | - `part` (Block List) A nested block type which adds a file to the generated cloud-init configuration. Use multiple `part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document. (see [below for nested schema](#nestedblock--part))
82 |
83 | ### Optional
84 |
85 | - `base64_encode` (Boolean) Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.
86 | - `boundary` (String) Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.
87 | - `gzip` (Boolean) Specify whether or not to gzip the `rendered` output. Defaults to `true`.
88 |
89 | ### Read-Only
90 |
91 | - `id` (String) [CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.
92 | - `rendered` (String) The final rendered multi-part cloud-init config.
93 |
94 |
95 | ### Nested Schema for `part`
96 |
97 | Required:
98 |
99 | - `content` (String) Body content for the part.
100 |
101 | Optional:
102 |
103 | - `content_type` (String) A MIME-style content type to report in the header for the part. Defaults to `text/plain`
104 | - `filename` (String) A filename to report in the header for the part.
105 | - `merge_type` (String) A value for the `X-Merge-Type` header of the part, to control [cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).
106 |
107 |
--------------------------------------------------------------------------------
/docs/cdktf/python/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit Provider"
3 | description: |-
4 | The cloud-init Terraform provider exposes the cloudinit_config data source, previously available as the template_cloudinit_config resource in the template provider https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/cloudinit_config, which renders a multipart MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | ---
6 |
7 |
8 |
9 | # cloudinit Provider
10 |
11 | The cloud-init Terraform provider exposes the `cloudinit_config` data source, previously available as the `template_cloudinit_config` resource [in the template provider](https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/cloudinit_config), which renders a [multipart MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
12 |
13 | This provider requires no configuration. For information on the resources it provides, see the navigation bar.
14 |
--------------------------------------------------------------------------------
/docs/cdktf/python/resources/config.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit_config Resource - terraform-provider-cloudinit"
3 | description: |-
4 | Renders a multi-part MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as user_data for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see User-Data Formats https://cloudinit.readthedocs.io/en/latest/explanation/format.html in the cloud-init manual.
6 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
7 | ---
8 |
9 |
10 |
11 | # cloudinit_config (Resource)
12 |
13 | ~> **This resource is deprecated** Please use the [cloudinit_config](https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs/data-sources/config)
14 | data source instead.
15 |
16 | Renders a [multi-part MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
17 |
18 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as `user_data` for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see [User-Data Formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) in the cloud-init manual.
19 |
20 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
21 |
22 | ## Example Usage
23 |
24 | ### Config
25 | ```python
26 | # DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
27 | from constructs import Construct
28 | from cdktf import Fn, Token, TerraformStack
29 | #
30 | # Provider bindings are generated by running `cdktf get`.
31 | # See https://cdk.tf/provider-generation for more details.
32 | #
33 | from imports.cloudinit.config import Config
34 | class MyConvertedCode(TerraformStack):
35 | def __init__(self, scope, name):
36 | super().__init__(scope, name)
37 | Config(self, "foobar",
38 | base64_encode=False,
39 | gzip=False,
40 | part=[ConfigPart(
41 | content=Token.as_string(Fn.file("${path.module}/hello-script.sh")),
42 | content_type="text/x-shellscript",
43 | filename="hello-script.sh"
44 | ), ConfigPart(
45 | content=Token.as_string(Fn.file("${path.module}/cloud-config.yaml")),
46 | content_type="text/cloud-config",
47 | filename="cloud-config.yaml"
48 | )
49 | ]
50 | )
51 | ```
52 |
53 | ### hello-script.sh
54 | ```shell
55 | #!/bin/sh
56 | echo "Hello World! I'm starting up now at $(date -R)!"
57 | ```
58 |
59 | ### cloud-config.yaml
60 | ```yaml
61 | #cloud-config
62 | # See documentation for more configuration examples
63 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html
64 |
65 | # Install arbitrary packages
66 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#install-arbitrary-packages
67 | packages:
68 | - python
69 | # Run commands on first boot
70 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#run-commands-on-first-boot
71 | runcmd:
72 | - [ ls, -l, / ]
73 | - [ sh, -xc, "echo $(date) ': hello world!'" ]
74 | - [ sh, -c, echo "=========hello world=========" ]
75 | - ls -l /root
76 | ```
77 |
78 |
79 |
80 | ## Schema
81 |
82 | ### Required
83 |
84 | - `part` (Block List) A nested block type which adds a file to the generated cloud-init configuration. Use multiple `part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document. (see [below for nested schema](#nestedblock--part))
85 |
86 | ### Optional
87 |
88 | - `base64_encode` (Boolean) Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.
89 | - `boundary` (String) Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.
90 | - `gzip` (Boolean) Specify whether or not to gzip the `rendered` output. Defaults to `true`.
91 |
92 | ### Read-Only
93 |
94 | - `id` (String) [CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.
95 | - `rendered` (String) The final rendered multi-part cloud-init config.
96 |
97 |
98 | ### Nested Schema for `part`
99 |
100 | Required:
101 |
102 | - `content` (String) Body content for the part.
103 |
104 | Optional:
105 |
106 | - `content_type` (String) A MIME-style content type to report in the header for the part. Defaults to `text/plain`
107 | - `filename` (String) A filename to report in the header for the part.
108 | - `merge_type` (String) A value for the `X-Merge-Type` header of the part, to control [cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).
109 |
110 |
--------------------------------------------------------------------------------
/docs/cdktf/typescript/data-sources/config.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit_config Data Source - terraform-provider-cloudinit"
3 | description: |-
4 | Renders a multi-part MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as user_data for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see User-Data Formats https://cloudinit.readthedocs.io/en/latest/explanation/format.html in the cloud-init manual.
6 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
7 | ---
8 |
9 |
10 |
11 | # cloudinit_config (Data Source)
12 |
13 | Renders a [multi-part MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
14 |
15 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as `userData` for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see [User-Data Formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) in the cloud-init manual.
16 |
17 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
18 |
19 | ## Example Usage
20 |
21 | ### Config
22 | ```typescript
23 | // DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
24 | import { Construct } from "constructs";
25 | import { Fn, Token, TerraformStack } from "cdktf";
26 | /*
27 | * Provider bindings are generated by running `cdktf get`.
28 | * See https://cdk.tf/provider-generation for more details.
29 | */
30 | import { DataCloudinitConfig } from "./.gen/providers/cloudinit/data-cloudinit-config";
31 | class MyConvertedCode extends TerraformStack {
32 | constructor(scope: Construct, name: string) {
33 | super(scope, name);
34 | new DataCloudinitConfig(this, "foobar", {
35 | base64Encode: false,
36 | gzip: false,
37 | part: [
38 | {
39 | content: Token.asString(Fn.file("${path.module}/hello-script.sh")),
40 | contentType: "text/x-shellscript",
41 | filename: "hello-script.sh",
42 | },
43 | {
44 | content: Token.asString(Fn.file("${path.module}/cloud-config.yaml")),
45 | contentType: "text/cloud-config",
46 | filename: "cloud-config.yaml",
47 | },
48 | ],
49 | });
50 | }
51 | }
52 |
53 | ```
54 |
55 | ### hello-script.sh
56 | ```shell
57 | #!/bin/sh
58 | echo "Hello World! I'm starting up now at $(date -R)!"
59 | ```
60 |
61 | ### cloud-config.yaml
62 | ```yaml
63 | #cloud-config
64 | # See documentation for more configuration examples
65 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html
66 |
67 | # Install arbitrary packages
68 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#install-arbitrary-packages
69 | packages:
70 | - python
71 | # Run commands on first boot
72 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#run-commands-on-first-boot
73 | runcmd:
74 | - [ ls, -l, / ]
75 | - [ sh, -xc, "echo $(date) ': hello world!'" ]
76 | - [ sh, -c, echo "=========hello world=========" ]
77 | - ls -l /root
78 | ```
79 |
80 |
81 |
82 | ## Schema
83 |
84 | ### Required
85 |
86 | - `part` (Block List) A nested block type which adds a file to the generated cloud-init configuration. Use multiple `part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document. (see [below for nested schema](#nestedblock--part))
87 |
88 | ### Optional
89 |
90 | - `base64Encode` (Boolean) Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.
91 | - `boundary` (String) Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.
92 | - `gzip` (Boolean) Specify whether or not to gzip the `rendered` output. Defaults to `true`.
93 |
94 | ### Read-Only
95 |
96 | - `id` (String) [CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.
97 | - `rendered` (String) The final rendered multi-part cloud-init config.
98 |
99 |
100 | ### Nested Schema for `part`
101 |
102 | Required:
103 |
104 | - `content` (String) Body content for the part.
105 |
106 | Optional:
107 |
108 | - `contentType` (String) A MIME-style content type to report in the header for the part. Defaults to `text/plain`
109 | - `filename` (String) A filename to report in the header for the part.
110 | - `mergeType` (String) A value for the `X-Merge-Type` header of the part, to control [cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).
111 |
112 |
--------------------------------------------------------------------------------
/docs/cdktf/typescript/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit Provider"
3 | description: |-
4 | The cloud-init Terraform provider exposes the cloudinit_config data source, previously available as the template_cloudinit_config resource in the template provider https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/cloudinit_config, which renders a multipart MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | ---
6 |
7 |
8 |
9 | # cloudinit Provider
10 |
11 | The cloud-init Terraform provider exposes the `cloudinit_config` data source, previously available as the `template_cloudinit_config` resource [in the template provider](https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/cloudinit_config), which renders a [multipart MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
12 |
13 | This provider requires no configuration. For information on the resources it provides, see the navigation bar.
14 |
--------------------------------------------------------------------------------
/docs/cdktf/typescript/resources/config.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit_config Resource - terraform-provider-cloudinit"
3 | description: |-
4 | Renders a multi-part MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as user_data for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see User-Data Formats https://cloudinit.readthedocs.io/en/latest/explanation/format.html in the cloud-init manual.
6 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
7 | ---
8 |
9 |
10 |
11 | # cloudinit_config (Resource)
12 |
13 | ~> **This resource is deprecated** Please use the [cloudinit_config](https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs/data-sources/config)
14 | data source instead.
15 |
16 | Renders a [multi-part MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
17 |
18 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as `userData` for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see [User-Data Formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) in the cloud-init manual.
19 |
20 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
21 |
22 | ## Example Usage
23 |
24 | ### Config
25 | ```typescript
26 | // DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
27 | import { Construct } from "constructs";
28 | import { Fn, Token, TerraformStack } from "cdktf";
29 | /*
30 | * Provider bindings are generated by running `cdktf get`.
31 | * See https://cdk.tf/provider-generation for more details.
32 | */
33 | import { Config } from "./.gen/providers/cloudinit/config";
34 | class MyConvertedCode extends TerraformStack {
35 | constructor(scope: Construct, name: string) {
36 | super(scope, name);
37 | new Config(this, "foobar", {
38 | base64Encode: false,
39 | gzip: false,
40 | part: [
41 | {
42 | content: Token.asString(Fn.file("${path.module}/hello-script.sh")),
43 | contentType: "text/x-shellscript",
44 | filename: "hello-script.sh",
45 | },
46 | {
47 | content: Token.asString(Fn.file("${path.module}/cloud-config.yaml")),
48 | contentType: "text/cloud-config",
49 | filename: "cloud-config.yaml",
50 | },
51 | ],
52 | });
53 | }
54 | }
55 |
56 | ```
57 |
58 | ### hello-script.sh
59 | ```shell
60 | #!/bin/sh
61 | echo "Hello World! I'm starting up now at $(date -R)!"
62 | ```
63 |
64 | ### cloud-config.yaml
65 | ```yaml
66 | #cloud-config
67 | # See documentation for more configuration examples
68 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html
69 |
70 | # Install arbitrary packages
71 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#install-arbitrary-packages
72 | packages:
73 | - python
74 | # Run commands on first boot
75 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#run-commands-on-first-boot
76 | runcmd:
77 | - [ ls, -l, / ]
78 | - [ sh, -xc, "echo $(date) ': hello world!'" ]
79 | - [ sh, -c, echo "=========hello world=========" ]
80 | - ls -l /root
81 | ```
82 |
83 |
84 |
85 | ## Schema
86 |
87 | ### Required
88 |
89 | - `part` (Block List) A nested block type which adds a file to the generated cloud-init configuration. Use multiple `part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document. (see [below for nested schema](#nestedblock--part))
90 |
91 | ### Optional
92 |
93 | - `base64Encode` (Boolean) Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.
94 | - `boundary` (String) Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.
95 | - `gzip` (Boolean) Specify whether or not to gzip the `rendered` output. Defaults to `true`.
96 |
97 | ### Read-Only
98 |
99 | - `id` (String) [CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.
100 | - `rendered` (String) The final rendered multi-part cloud-init config.
101 |
102 |
103 | ### Nested Schema for `part`
104 |
105 | Required:
106 |
107 | - `content` (String) Body content for the part.
108 |
109 | Optional:
110 |
111 | - `contentType` (String) A MIME-style content type to report in the header for the part. Defaults to `text/plain`
112 | - `filename` (String) A filename to report in the header for the part.
113 | - `mergeType` (String) A value for the `X-Merge-Type` header of the part, to control [cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).
114 |
115 |
--------------------------------------------------------------------------------
/docs/data-sources/config.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit_config Data Source - terraform-provider-cloudinit"
3 | description: |-
4 | Renders a multi-part MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as user_data for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see User-Data Formats https://cloudinit.readthedocs.io/en/latest/explanation/format.html in the cloud-init manual.
6 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
7 | ---
8 |
9 | # cloudinit_config (Data Source)
10 |
11 | Renders a [multi-part MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
12 |
13 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as `user_data` for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see [User-Data Formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) in the cloud-init manual.
14 |
15 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
16 |
17 | ## Example Usage
18 |
19 | ### Config
20 | ```terraform
21 | data "cloudinit_config" "foobar" {
22 | gzip = false
23 | base64_encode = false
24 |
25 | part {
26 | filename = "hello-script.sh"
27 | content_type = "text/x-shellscript"
28 |
29 | content = file("${path.module}/hello-script.sh")
30 | }
31 |
32 | part {
33 | filename = "cloud-config.yaml"
34 | content_type = "text/cloud-config"
35 |
36 | content = file("${path.module}/cloud-config.yaml")
37 | }
38 | }
39 | ```
40 |
41 | ### hello-script.sh
42 | ```shell
43 | #!/bin/sh
44 | echo "Hello World! I'm starting up now at $(date -R)!"
45 | ```
46 |
47 | ### cloud-config.yaml
48 | ```yaml
49 | #cloud-config
50 | # See documentation for more configuration examples
51 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html
52 |
53 | # Install arbitrary packages
54 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#install-arbitrary-packages
55 | packages:
56 | - python
57 | # Run commands on first boot
58 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#run-commands-on-first-boot
59 | runcmd:
60 | - [ ls, -l, / ]
61 | - [ sh, -xc, "echo $(date) ': hello world!'" ]
62 | - [ sh, -c, echo "=========hello world=========" ]
63 | - ls -l /root
64 | ```
65 |
66 |
67 |
68 | ## Schema
69 |
70 | ### Required
71 |
72 | - `part` (Block List) A nested block type which adds a file to the generated cloud-init configuration. Use multiple `part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document. (see [below for nested schema](#nestedblock--part))
73 |
74 | ### Optional
75 |
76 | - `base64_encode` (Boolean) Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.
77 | - `boundary` (String) Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.
78 | - `gzip` (Boolean) Specify whether or not to gzip the `rendered` output. Defaults to `true`.
79 |
80 | ### Read-Only
81 |
82 | - `id` (String) [CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.
83 | - `rendered` (String) The final rendered multi-part cloud-init config.
84 |
85 |
86 | ### Nested Schema for `part`
87 |
88 | Required:
89 |
90 | - `content` (String) Body content for the part.
91 |
92 | Optional:
93 |
94 | - `content_type` (String) A MIME-style content type to report in the header for the part. Defaults to `text/plain`
95 | - `filename` (String) A filename to report in the header for the part.
96 | - `merge_type` (String) A value for the `X-Merge-Type` header of the part, to control [cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).
97 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit Provider"
3 | description: |-
4 | The cloud-init Terraform provider exposes the cloudinit_config data source, previously available as the template_cloudinit_config resource in the template provider https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/cloudinit_config, which renders a multipart MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | ---
6 |
7 | # cloudinit Provider
8 |
9 | The cloud-init Terraform provider exposes the `cloudinit_config` data source, previously available as the `template_cloudinit_config` resource [in the template provider](https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/cloudinit_config), which renders a [multipart MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
10 |
11 | This provider requires no configuration. For information on the resources it provides, see the navigation bar.
--------------------------------------------------------------------------------
/docs/resources/config.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "cloudinit_config Resource - terraform-provider-cloudinit"
3 | description: |-
4 | Renders a multi-part MIME configuration https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive for use with cloud-init https://cloudinit.readthedocs.io/en/latest/.
5 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as user_data for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see User-Data Formats https://cloudinit.readthedocs.io/en/latest/explanation/format.html in the cloud-init manual.
6 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
7 | ---
8 |
9 | # cloudinit_config (Resource)
10 |
11 | ~> **This resource is deprecated** Please use the [cloudinit_config](https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs/data-sources/config)
12 | data source instead.
13 |
14 | Renders a [multi-part MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).
15 |
16 | Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific user data mechanisms, such as `user_data` for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, see [User-Data Formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) in the cloud-init manual.
17 |
18 | This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.
19 |
20 | ## Example Usage
21 |
22 | ### Config
23 | ```terraform
24 | resource "cloudinit_config" "foobar" {
25 | gzip = false
26 | base64_encode = false
27 |
28 | part {
29 | filename = "hello-script.sh"
30 | content_type = "text/x-shellscript"
31 |
32 | content = file("${path.module}/hello-script.sh")
33 | }
34 |
35 | part {
36 | filename = "cloud-config.yaml"
37 | content_type = "text/cloud-config"
38 |
39 | content = file("${path.module}/cloud-config.yaml")
40 | }
41 | }
42 | ```
43 |
44 | ### hello-script.sh
45 | ```shell
46 | #!/bin/sh
47 | echo "Hello World! I'm starting up now at $(date -R)!"
48 | ```
49 |
50 | ### cloud-config.yaml
51 | ```yaml
52 | #cloud-config
53 | # See documentation for more configuration examples
54 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html
55 |
56 | # Install arbitrary packages
57 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#install-arbitrary-packages
58 | packages:
59 | - python
60 | # Run commands on first boot
61 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#run-commands-on-first-boot
62 | runcmd:
63 | - [ ls, -l, / ]
64 | - [ sh, -xc, "echo $(date) ': hello world!'" ]
65 | - [ sh, -c, echo "=========hello world=========" ]
66 | - ls -l /root
67 | ```
68 |
69 |
70 |
71 | ## Schema
72 |
73 | ### Required
74 |
75 | - `part` (Block List) A nested block type which adds a file to the generated cloud-init configuration. Use multiple `part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document. (see [below for nested schema](#nestedblock--part))
76 |
77 | ### Optional
78 |
79 | - `base64_encode` (Boolean) Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.
80 | - `boundary` (String) Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.
81 | - `gzip` (Boolean) Specify whether or not to gzip the `rendered` output. Defaults to `true`.
82 |
83 | ### Read-Only
84 |
85 | - `id` (String) [CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.
86 | - `rendered` (String) The final rendered multi-part cloud-init config.
87 |
88 |
89 | ### Nested Schema for `part`
90 |
91 | Required:
92 |
93 | - `content` (String) Body content for the part.
94 |
95 | Optional:
96 |
97 | - `content_type` (String) A MIME-style content type to report in the header for the part. Defaults to `text/plain`
98 | - `filename` (String) A filename to report in the header for the part.
99 | - `merge_type` (String) A value for the `X-Merge-Type` header of the part, to control [cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).
100 |
--------------------------------------------------------------------------------
/examples/data-sources/cloudinit_config/cloud-config.yaml:
--------------------------------------------------------------------------------
1 | #cloud-config
2 | # See documentation for more configuration examples
3 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html
4 |
5 | # Install arbitrary packages
6 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#install-arbitrary-packages
7 | packages:
8 | - python
9 | # Run commands on first boot
10 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#run-commands-on-first-boot
11 | runcmd:
12 | - [ ls, -l, / ]
13 | - [ sh, -xc, "echo $(date) ': hello world!'" ]
14 | - [ sh, -c, echo "=========hello world=========" ]
15 | - ls -l /root
--------------------------------------------------------------------------------
/examples/data-sources/cloudinit_config/data-source.tf:
--------------------------------------------------------------------------------
1 | data "cloudinit_config" "foobar" {
2 | gzip = false
3 | base64_encode = false
4 |
5 | part {
6 | filename = "hello-script.sh"
7 | content_type = "text/x-shellscript"
8 |
9 | content = file("${path.module}/hello-script.sh")
10 | }
11 |
12 | part {
13 | filename = "cloud-config.yaml"
14 | content_type = "text/cloud-config"
15 |
16 | content = file("${path.module}/cloud-config.yaml")
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/data-sources/cloudinit_config/hello-script.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | echo "Hello World! I'm starting up now at $(date -R)!"
3 |
--------------------------------------------------------------------------------
/examples/resources/cloudinit_config/cloud-config.yaml:
--------------------------------------------------------------------------------
1 | #cloud-config
2 | # See documentation for more configuration examples
3 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html
4 |
5 | # Install arbitrary packages
6 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#install-arbitrary-packages
7 | packages:
8 | - python
9 | # Run commands on first boot
10 | # https://cloudinit.readthedocs.io/en/latest/reference/examples.html#run-commands-on-first-boot
11 | runcmd:
12 | - [ ls, -l, / ]
13 | - [ sh, -xc, "echo $(date) ': hello world!'" ]
14 | - [ sh, -c, echo "=========hello world=========" ]
15 | - ls -l /root
--------------------------------------------------------------------------------
/examples/resources/cloudinit_config/hello-script.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | echo "Hello World! I'm starting up now at $(date -R)!"
3 |
--------------------------------------------------------------------------------
/examples/resources/cloudinit_config/resource.tf:
--------------------------------------------------------------------------------
1 | resource "cloudinit_config" "foobar" {
2 | gzip = false
3 | base64_encode = false
4 |
5 | part {
6 | filename = "hello-script.sh"
7 | content_type = "text/x-shellscript"
8 |
9 | content = file("${path.module}/hello-script.sh")
10 | }
11 |
12 | part {
13 | filename = "cloud-config.yaml"
14 | content_type = "text/cloud-config"
15 |
16 | content = file("${path.module}/cloud-config.yaml")
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/hashicorp/terraform-provider-cloudinit
2 |
3 | go 1.23.7
4 |
5 | require (
6 | github.com/hashicorp/terraform-plugin-framework v1.15.0
7 | github.com/hashicorp/terraform-plugin-framework-validators v0.18.0
8 | github.com/hashicorp/terraform-plugin-go v0.28.0
9 | github.com/hashicorp/terraform-plugin-log v0.9.0
10 | github.com/hashicorp/terraform-plugin-testing v1.13.2
11 | )
12 |
13 | require (
14 | github.com/ProtonMail/go-crypto v1.1.6 // indirect
15 | github.com/agext/levenshtein v1.2.2 // indirect
16 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
17 | github.com/cloudflare/circl v1.6.1 // indirect
18 | github.com/fatih/color v1.16.0 // indirect
19 | github.com/golang/protobuf v1.5.4 // indirect
20 | github.com/google/go-cmp v0.7.0 // indirect
21 | github.com/hashicorp/errwrap v1.1.0 // indirect
22 | github.com/hashicorp/go-checkpoint v0.5.0 // indirect
23 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
24 | github.com/hashicorp/go-cty v1.5.0 // indirect
25 | github.com/hashicorp/go-hclog v1.6.3 // indirect
26 | github.com/hashicorp/go-multierror v1.1.1 // indirect
27 | github.com/hashicorp/go-plugin v1.6.3 // indirect
28 | github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
29 | github.com/hashicorp/go-uuid v1.0.3 // indirect
30 | github.com/hashicorp/go-version v1.7.0 // indirect
31 | github.com/hashicorp/hc-install v0.9.2 // indirect
32 | github.com/hashicorp/hcl/v2 v2.23.0 // indirect
33 | github.com/hashicorp/logutils v1.0.0 // indirect
34 | github.com/hashicorp/terraform-exec v0.23.0 // indirect
35 | github.com/hashicorp/terraform-json v0.25.0 // indirect
36 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 // indirect
37 | github.com/hashicorp/terraform-registry-address v0.2.5 // indirect
38 | github.com/hashicorp/terraform-svchost v0.1.1 // indirect
39 | github.com/hashicorp/yamux v0.1.1 // indirect
40 | github.com/kr/pretty v0.3.0 // indirect
41 | github.com/mattn/go-colorable v0.1.13 // indirect
42 | github.com/mattn/go-isatty v0.0.20 // indirect
43 | github.com/mitchellh/copystructure v1.2.0 // indirect
44 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect
45 | github.com/mitchellh/go-wordwrap v1.0.0 // indirect
46 | github.com/mitchellh/mapstructure v1.5.0 // indirect
47 | github.com/mitchellh/reflectwalk v1.0.2 // indirect
48 | github.com/oklog/run v1.0.0 // indirect
49 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
50 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
51 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
52 | github.com/zclconf/go-cty v1.16.3 // indirect
53 | golang.org/x/crypto v0.39.0 // indirect
54 | golang.org/x/mod v0.25.0 // indirect
55 | golang.org/x/net v0.40.0 // indirect
56 | golang.org/x/sync v0.15.0 // indirect
57 | golang.org/x/sys v0.33.0 // indirect
58 | golang.org/x/text v0.26.0 // indirect
59 | golang.org/x/tools v0.33.0 // indirect
60 | google.golang.org/appengine v1.6.8 // indirect
61 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
62 | google.golang.org/grpc v1.72.1 // indirect
63 | google.golang.org/protobuf v1.36.6 // indirect
64 | )
65 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
2 | dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
3 | github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
4 | github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
5 | github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
6 | github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
7 | github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
8 | github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
9 | github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
10 | github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
11 | github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
12 | github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
13 | github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
14 | github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
15 | github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
16 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
17 | github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
18 | github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
19 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
20 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
21 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
22 | github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
23 | github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
24 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
25 | github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
26 | github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
27 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
28 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
29 | github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
30 | github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
31 | github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
32 | github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
33 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
34 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
35 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
36 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
37 | github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
38 | github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
39 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
40 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
41 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
42 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
43 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
44 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
45 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
46 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
47 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
48 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
49 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
50 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
51 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
52 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
53 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
54 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
55 | github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
56 | github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
57 | github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
58 | github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
59 | github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
60 | github.com/hashicorp/go-cty v1.5.0 h1:EkQ/v+dDNUqnuVpmS5fPqyY71NXVgT5gf32+57xY8g0=
61 | github.com/hashicorp/go-cty v1.5.0/go.mod h1:lFUCG5kd8exDobgSfyj4ONE/dc822kiYMguVKdHGMLM=
62 | github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
63 | github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
64 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
65 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
66 | github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg=
67 | github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0=
68 | github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
69 | github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
70 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
71 | github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
72 | github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
73 | github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
74 | github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
75 | github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24=
76 | github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I=
77 | github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
78 | github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
79 | github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
80 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
81 | github.com/hashicorp/terraform-exec v0.23.0 h1:MUiBM1s0CNlRFsCLJuM5wXZrzA3MnPYEsiXmzATMW/I=
82 | github.com/hashicorp/terraform-exec v0.23.0/go.mod h1:mA+qnx1R8eePycfwKkCRk3Wy65mwInvlpAeOwmA7vlY=
83 | github.com/hashicorp/terraform-json v0.25.0 h1:rmNqc/CIfcWawGiwXmRuiXJKEiJu1ntGoxseG1hLhoQ=
84 | github.com/hashicorp/terraform-json v0.25.0/go.mod h1:sMKS8fiRDX4rVlR6EJUMudg1WcanxCMoWwTLkgZP/vc=
85 | github.com/hashicorp/terraform-plugin-framework v1.15.0 h1:LQ2rsOfmDLxcn5EeIwdXFtr03FVsNktbbBci8cOKdb4=
86 | github.com/hashicorp/terraform-plugin-framework v1.15.0/go.mod h1:hxrNI/GY32KPISpWqlCoTLM9JZsGH3CyYlir09bD/fI=
87 | github.com/hashicorp/terraform-plugin-framework-validators v0.18.0 h1:OQnlOt98ua//rCw+QhBbSqfW3QbwtVrcdWeQN5gI3Hw=
88 | github.com/hashicorp/terraform-plugin-framework-validators v0.18.0/go.mod h1:lZvZvagw5hsJwuY7mAY6KUz45/U6fiDR0CzQAwWD0CA=
89 | github.com/hashicorp/terraform-plugin-go v0.28.0 h1:zJmu2UDwhVN0J+J20RE5huiF3XXlTYVIleaevHZgKPA=
90 | github.com/hashicorp/terraform-plugin-go v0.28.0/go.mod h1:FDa2Bb3uumkTGSkTFpWSOwWJDwA7bf3vdP3ltLDTH6o=
91 | github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
92 | github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
93 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 h1:NFPMacTrY/IdcIcnUB+7hsore1ZaRWU9cnB6jFoBnIM=
94 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0/go.mod h1:QYmYnLfsosrxjCnGY1p9c7Zj6n9thnEE+7RObeYs3fA=
95 | github.com/hashicorp/terraform-plugin-testing v1.13.2 h1:mSotG4Odl020vRjIenA3rggwo6Kg6XCKIwtRhYgp+/M=
96 | github.com/hashicorp/terraform-plugin-testing v1.13.2/go.mod h1:WHQ9FDdiLoneey2/QHpGM/6SAYf4A7AZazVg7230pLE=
97 | github.com/hashicorp/terraform-registry-address v0.2.5 h1:2GTftHqmUhVOeuu9CW3kwDkRe4pcBDq0uuK5VJngU1M=
98 | github.com/hashicorp/terraform-registry-address v0.2.5/go.mod h1:PpzXWINwB5kuVS5CA7m1+eO2f1jKb5ZDIxrOPfpnGkg=
99 | github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
100 | github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
101 | github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
102 | github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
103 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
104 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
105 | github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
106 | github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
107 | github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
108 | github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
109 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
110 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
111 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
112 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
113 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
114 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
115 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
116 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
117 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
118 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
119 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
120 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
121 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
122 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
123 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
124 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
125 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
126 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
127 | github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
128 | github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
129 | github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
130 | github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
131 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
132 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
133 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
134 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
135 | github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
136 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
137 | github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
138 | github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
139 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
140 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
141 | github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
142 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
143 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
144 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
145 | github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
146 | github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
147 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
148 | github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
149 | github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
150 | github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
151 | github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
152 | github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
153 | github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
154 | github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
155 | github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
156 | github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
157 | github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
158 | github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
159 | github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
160 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
161 | github.com/zclconf/go-cty v1.16.3 h1:osr++gw2T61A8KVYHoQiFbFd1Lh3JOCXc/jFLJXKTxk=
162 | github.com/zclconf/go-cty v1.16.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
163 | github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
164 | github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
165 | go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
166 | go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
167 | go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
168 | go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
169 | go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
170 | go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
171 | go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
172 | go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
173 | go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
174 | go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
175 | go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
176 | go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
177 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
178 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
179 | golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
180 | golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
181 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
182 | golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
183 | golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
184 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
185 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
186 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
187 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
188 | golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
189 | golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
190 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
191 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
192 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
193 | golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
194 | golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
195 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
196 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
197 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
198 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
199 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
200 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
201 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
202 | golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
203 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
204 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
205 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
206 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
207 | golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
208 | golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
209 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
210 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
211 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
212 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
213 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
214 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
215 | golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
216 | golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
217 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
218 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
219 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
220 | golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
221 | golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
222 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
223 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
224 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
225 | google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
226 | google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
227 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
228 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
229 | google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
230 | google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
231 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
232 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
233 | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
234 | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
235 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
236 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
237 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
238 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
239 | gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
240 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
241 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
242 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
243 |
--------------------------------------------------------------------------------
/internal/hashcode/hashcode.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package hashcode
5 |
6 | import (
7 | "bytes"
8 | "fmt"
9 | "hash/crc32"
10 | )
11 |
12 | // String hashes a string to a unique hashcode.
13 | //
14 | // crc32 returns a uint32, but for our use we need
15 | // and non negative integer. Here we cast to an integer
16 | // and invert it if the result is negative.
17 | func String(s string) int {
18 | v := int(crc32.ChecksumIEEE([]byte(s)))
19 | if v >= 0 {
20 | return v
21 | }
22 | if -v >= 0 {
23 | return -v
24 | }
25 | // v == MinInt
26 | return 0
27 | }
28 |
29 | // Strings hashes a list of strings to a unique hashcode.
30 | func Strings(strings []string) string {
31 | var buf bytes.Buffer
32 |
33 | for _, s := range strings {
34 | buf.WriteString(fmt.Sprintf("%s-", s))
35 | }
36 |
37 | return fmt.Sprintf("%d", String(buf.String()))
38 | }
39 |
--------------------------------------------------------------------------------
/internal/hashcode/hashcode_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package hashcode
5 |
6 | import (
7 | "testing"
8 | )
9 |
10 | func TestString(t *testing.T) {
11 | v := "hello, world"
12 | expected := String(v)
13 | for i := 0; i < 100; i++ {
14 | actual := String(v)
15 | if actual != expected {
16 | t.Fatalf("bad: %#v\n\t%#v", actual, expected)
17 | }
18 | }
19 | }
20 |
21 | func TestStrings(t *testing.T) {
22 | v := []string{"hello", ",", "world"}
23 | expected := Strings(v)
24 | for i := 0; i < 100; i++ {
25 | actual := Strings(v)
26 | if actual != expected {
27 | t.Fatalf("bad: %#v\n\t%#v", actual, expected)
28 | }
29 | }
30 | }
31 |
32 | func TestString_positiveIndex(t *testing.T) {
33 | // "2338615298" hashes to uint32(2147483648) which is math.MinInt32
34 | ips := []string{"192.168.1.3", "192.168.1.5", "2338615298"}
35 | for _, ip := range ips {
36 | if index := String(ip); index < 0 {
37 | t.Fatalf("Bad Index %#v for ip %s", index, ip)
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/internal/provider/cloudinit_config.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package provider
5 |
6 | import (
7 | "bytes"
8 | "compress/gzip"
9 | "context"
10 | "encoding/base64"
11 | "fmt"
12 | "io"
13 | "mime/multipart"
14 | "net/textproto"
15 | "strconv"
16 |
17 | "github.com/hashicorp/terraform-plugin-framework/diag"
18 | "github.com/hashicorp/terraform-plugin-framework/path"
19 | "github.com/hashicorp/terraform-plugin-framework/types"
20 | "github.com/hashicorp/terraform-plugin-log/tflog"
21 |
22 | "github.com/hashicorp/terraform-provider-cloudinit/internal/hashcode"
23 | )
24 |
25 | // Model and functionality of data source and resource are equivalent.
26 | type configModel struct {
27 | ID types.String `tfsdk:"id"`
28 | Parts types.List `tfsdk:"part"` // configPartModel
29 | Gzip types.Bool `tfsdk:"gzip"`
30 | Base64Encode types.Bool `tfsdk:"base64_encode"`
31 | Boundary types.String `tfsdk:"boundary"`
32 | Rendered types.String `tfsdk:"rendered"`
33 | }
34 |
35 | type configPartModel struct {
36 | ContentType types.String `tfsdk:"content_type"`
37 | Content types.String `tfsdk:"content"`
38 | FileName types.String `tfsdk:"filename"`
39 | MergeType types.String `tfsdk:"merge_type"`
40 | }
41 |
42 | func (c *configModel) setDefaults(ctx context.Context) diag.Diagnostics {
43 | var diags diag.Diagnostics
44 |
45 | if c.Gzip.IsNull() {
46 | c.Gzip = types.BoolValue(true)
47 | }
48 | if c.Base64Encode.IsNull() {
49 | c.Base64Encode = types.BoolValue(true)
50 | }
51 | if c.Boundary.IsNull() {
52 | c.Boundary = types.StringValue("MIMEBOUNDARY")
53 | }
54 |
55 | if c.Parts.IsNull() || c.Parts.IsUnknown() {
56 | return diags
57 | }
58 |
59 | var configParts []configPartModel
60 | diags.Append(c.Parts.ElementsAs(ctx, &configParts, false)...)
61 | if diags.HasError() {
62 | return diags
63 | }
64 |
65 | for i, part := range configParts {
66 | if part.ContentType.IsNull() || part.ContentType.ValueString() == "" {
67 | configParts[i].ContentType = types.StringValue("text/plain")
68 | }
69 | }
70 |
71 | partsList, convertDiags := types.ListValueFrom(ctx, c.Parts.ElementType(ctx), configParts)
72 | diags.Append(convertDiags...)
73 | if diags.HasError() {
74 | return diags
75 | }
76 |
77 | c.Parts = partsList
78 |
79 | return diags
80 | }
81 |
82 | func (c configModel) validate(ctx context.Context) diag.Diagnostics {
83 | var diags diag.Diagnostics
84 |
85 | if c.Gzip.IsUnknown() || c.Base64Encode.IsUnknown() {
86 | return diags
87 | }
88 | diags.Append(c.setDefaults(ctx)...)
89 | if diags.HasError() {
90 | return diags
91 | }
92 |
93 | if c.Gzip.ValueBool() && !c.Base64Encode.ValueBool() {
94 | diags.AddAttributeError(
95 | path.Root("base64_encode"),
96 | "Invalid Attribute Configuration",
97 | "Expected base64_encode to be set to true when gzip is true.",
98 | )
99 | }
100 |
101 | return diags
102 | }
103 |
104 | func (c *configModel) update(ctx context.Context) diag.Diagnostics {
105 | var buffer bytes.Buffer
106 | var diags diag.Diagnostics
107 | var err error
108 |
109 | // cloudinit Provider 'v2.2.0' doesn't actually set default values in state properly, so we need to make sure
110 | // that we don't use any known empty values from previous versions of state
111 | diags.Append(c.setDefaults(ctx)...)
112 | if diags.HasError() {
113 | return diags
114 | }
115 |
116 | var configParts []configPartModel
117 | diags.Append(c.Parts.ElementsAs(ctx, &configParts, false)...)
118 | if diags.HasError() {
119 | return diags
120 | }
121 |
122 | if c.Gzip.ValueBool() {
123 | gzipWriter := gzip.NewWriter(&buffer)
124 |
125 | err = renderPartsToWriter(ctx, c.Boundary.ValueString(), configParts, gzipWriter)
126 |
127 | gzipWriter.Close()
128 | } else {
129 | err = renderPartsToWriter(ctx, c.Boundary.ValueString(), configParts, &buffer)
130 | }
131 |
132 | if err != nil {
133 | diags.AddError("Unable to render cloudinit config to MIME multi-part file", err.Error())
134 | return diags
135 | }
136 |
137 | output := ""
138 | if c.Base64Encode.ValueBool() {
139 | output = base64.StdEncoding.EncodeToString(buffer.Bytes())
140 | } else {
141 | output = buffer.String()
142 | }
143 |
144 | c.ID = types.StringValue(strconv.Itoa(hashcode.String(output)))
145 | c.Rendered = types.StringValue(output)
146 |
147 | return diags
148 | }
149 |
150 | func renderPartsToWriter(ctx context.Context, mimeBoundary string, parts []configPartModel, writer io.Writer) error {
151 | mimeWriter := multipart.NewWriter(writer)
152 | defer func() {
153 | err := mimeWriter.Close()
154 | if err != nil {
155 | tflog.Warn(ctx, fmt.Sprintf("error closing mimeWriter: %s", err))
156 | }
157 | }()
158 |
159 | // we need to set the boundary explicitly, otherwise the boundary is random
160 | // and this causes terraform to complain about the resource being different
161 | if err := mimeWriter.SetBoundary(mimeBoundary); err != nil {
162 | return err
163 | }
164 |
165 | _, err := writer.Write([]byte(fmt.Sprintf("Content-Type: multipart/mixed; boundary=\"%s\"\n", mimeWriter.Boundary())))
166 | if err != nil {
167 | return err
168 | }
169 |
170 | _, err = writer.Write([]byte("MIME-Version: 1.0\r\n\r\n"))
171 | if err != nil {
172 | return err
173 | }
174 |
175 | for _, part := range parts {
176 | header := textproto.MIMEHeader{}
177 |
178 | header.Set("Content-Type", part.ContentType.ValueString())
179 | header.Set("MIME-Version", "1.0")
180 | header.Set("Content-Transfer-Encoding", "7bit")
181 |
182 | if part.FileName.ValueString() != "" {
183 | header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, part.FileName.ValueString()))
184 | }
185 |
186 | if part.MergeType.ValueString() != "" {
187 | header.Set("X-Merge-Type", part.MergeType.ValueString())
188 | }
189 |
190 | partWriter, err := mimeWriter.CreatePart(header)
191 | if err != nil {
192 | return err
193 | }
194 |
195 | _, err = partWriter.Write([]byte(part.Content.ValueString()))
196 | if err != nil {
197 | return err
198 | }
199 | }
200 |
201 | return nil
202 | }
203 |
--------------------------------------------------------------------------------
/internal/provider/data_source_cloudinit_config.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package provider
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
10 | "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
11 | "github.com/hashicorp/terraform-plugin-framework/datasource"
12 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
13 | "github.com/hashicorp/terraform-plugin-framework/schema/validator"
14 | )
15 |
16 | var (
17 | _ datasource.DataSourceWithValidateConfig = (*configDataSource)(nil)
18 | )
19 |
20 | type configDataSource struct{}
21 |
22 | func (d *configDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
23 | resp.TypeName = req.ProviderTypeName + "_config"
24 | }
25 |
26 | func (d *configDataSource) ValidateConfig(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) {
27 | var cloudinitConfig configModel
28 |
29 | resp.Diagnostics.Append(req.Config.Get(ctx, &cloudinitConfig)...)
30 | if resp.Diagnostics.HasError() {
31 | return
32 | }
33 |
34 | resp.Diagnostics.Append(cloudinitConfig.validate(ctx)...)
35 | }
36 |
37 | func (d *configDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
38 | resp.Schema = schema.Schema{
39 | Blocks: map[string]schema.Block{
40 | "part": schema.ListNestedBlock{
41 | Validators: []validator.List{
42 | listvalidator.IsRequired(),
43 | },
44 | NestedObject: schema.NestedBlockObject{
45 | Attributes: map[string]schema.Attribute{
46 | "content_type": schema.StringAttribute{
47 | Validators: []validator.String{
48 | stringvalidator.LengthAtLeast(1),
49 | },
50 | Optional: true,
51 | Computed: true,
52 | MarkdownDescription: "A MIME-style content type to report in the header for the part. Defaults to `text/plain`",
53 | },
54 | "content": schema.StringAttribute{
55 | Required: true,
56 | MarkdownDescription: "Body content for the part.",
57 | },
58 | "filename": schema.StringAttribute{
59 | Optional: true,
60 | MarkdownDescription: "A filename to report in the header for the part.",
61 | },
62 | "merge_type": schema.StringAttribute{
63 | Optional: true,
64 | MarkdownDescription: "A value for the `X-Merge-Type` header of the part, to control " +
65 | "[cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).",
66 | },
67 | },
68 | },
69 | MarkdownDescription: "A nested block type which adds a file to the generated cloud-init configuration. Use multiple " +
70 | "`part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document.",
71 | },
72 | },
73 | Attributes: map[string]schema.Attribute{
74 | "gzip": schema.BoolAttribute{
75 | Optional: true,
76 | Computed: true,
77 | MarkdownDescription: "Specify whether or not to gzip the `rendered` output. Defaults to `true`.",
78 | },
79 | "base64_encode": schema.BoolAttribute{
80 | Optional: true,
81 | Computed: true,
82 | MarkdownDescription: "Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.",
83 | },
84 | "boundary": schema.StringAttribute{
85 | Validators: []validator.String{
86 | stringvalidator.LengthAtLeast(1),
87 | },
88 | Optional: true,
89 | Computed: true,
90 | MarkdownDescription: "Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.",
91 | },
92 | "rendered": schema.StringAttribute{
93 | Computed: true,
94 | MarkdownDescription: "The final rendered multi-part cloud-init config.",
95 | },
96 | "id": schema.StringAttribute{
97 | Computed: true,
98 | MarkdownDescription: "[CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.",
99 | },
100 | },
101 | MarkdownDescription: "Renders a [multi-part MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) " +
102 | "for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).\n\n" +
103 | "Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific " +
104 | "user data mechanisms, such as `user_data` for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, " +
105 | "see [User-Data Formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) in the cloud-init manual.\n\n" +
106 | "This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.",
107 | }
108 | }
109 |
110 | func (d *configDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
111 | var cloudinitConfig configModel
112 |
113 | resp.Diagnostics.Append(req.Config.Get(ctx, &cloudinitConfig)...)
114 | if resp.Diagnostics.HasError() {
115 | return
116 | }
117 |
118 | resp.Diagnostics.Append(cloudinitConfig.update(ctx)...)
119 | resp.Diagnostics.Append(resp.State.Set(ctx, cloudinitConfig)...)
120 | }
121 |
--------------------------------------------------------------------------------
/internal/provider/data_source_cloudinit_config_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package provider
5 |
6 | import (
7 | "regexp"
8 | "testing"
9 |
10 | r "github.com/hashicorp/terraform-plugin-testing/helper/resource"
11 | )
12 |
13 | func TestConfigDataSourceRender(t *testing.T) {
14 | testCases := []struct {
15 | Name string
16 | DataSourceBlock string
17 | Expected string
18 | }{
19 | {
20 | "no gzip or b64 - basic content",
21 | `data "cloudinit_config" "foo" {
22 | gzip = false
23 | base64_encode = false
24 |
25 | part {
26 | content_type = "text/x-shellscript"
27 | content = "baz"
28 | }
29 | }`,
30 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n",
31 | },
32 | {
33 | "no gzip or b64 - basic content - default to text plain",
34 | `data "cloudinit_config" "foo" {
35 | gzip = false
36 | base64_encode = false
37 |
38 | part {
39 | content = "baz"
40 | }
41 | }`,
42 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n",
43 | },
44 | {
45 | "no gzip or b64 - content with filename",
46 | `data "cloudinit_config" "foo" {
47 | gzip = false
48 | base64_encode = false
49 |
50 | part {
51 | content_type = "text/x-shellscript"
52 | content = "baz"
53 | filename = "foobar.sh"
54 | }
55 | }`,
56 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"foobar.sh\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n",
57 | },
58 | {
59 | "no gzip or b64 - two parts, basic content",
60 | `data "cloudinit_config" "foo" {
61 | gzip = false
62 | base64_encode = false
63 |
64 | part {
65 | content_type = "text/x-shellscript"
66 | content = "baz"
67 | }
68 | part {
69 | content_type = "text/x-shellscript"
70 | content = "ffbaz"
71 | }
72 | }`,
73 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nffbaz\r\n--MIMEBOUNDARY--\r\n",
74 | },
75 | {
76 | "no gzip or b64 - with boundary separator",
77 | `data "cloudinit_config" "foo" {
78 | gzip = false
79 | base64_encode = false
80 | boundary = "//"
81 |
82 | part {
83 | content_type = "text/x-shellscript"
84 | content = "baz"
85 | }
86 | }`,
87 | "Content-Type: multipart/mixed; boundary=\"//\"\nMIME-Version: 1.0\r\n\r\n--//\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--//--\r\n",
88 | },
89 | {
90 | "no gzip or b64 - two parts - all fields",
91 | `data "cloudinit_config" "foo" {
92 | gzip = false
93 | base64_encode = false
94 |
95 | part {
96 | content_type = "text/x-shellscript"
97 | content = "foo1"
98 | filename = "foofile1.txt"
99 | merge_type = "list()+dict()+str()"
100 | }
101 |
102 | part {
103 | content_type = "text/x-shellscript"
104 | content = "bar1"
105 | filename = "barfile1.txt"
106 | merge_type = "list()+dict()+str()"
107 | }
108 | }`,
109 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"foofile1.txt\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\nX-Merge-Type: list()+dict()+str()\r\n\r\nfoo1\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"barfile1.txt\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\nX-Merge-Type: list()+dict()+str()\r\n\r\nbar1\r\n--MIMEBOUNDARY--\r\n",
110 | },
111 | {
112 | "no gzip - b64 encoded - basic content",
113 | `data "cloudinit_config" "foo" {
114 | gzip = false
115 | base64_encode = true
116 |
117 | part {
118 | content_type = "text/x-shellscript"
119 | content = "heythere"
120 | }
121 | }`,
122 | "Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSJNSU1FQk9VTkRBUlkiCk1JTUUtVmVyc2lvbjogMS4wDQoNCi0tTUlNRUJPVU5EQVJZDQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA3Yml0DQpDb250ZW50LVR5cGU6IHRleHQveC1zaGVsbHNjcmlwdA0KTWltZS1WZXJzaW9uOiAxLjANCg0KaGV5dGhlcmUNCi0tTUlNRUJPVU5EQVJZLS0NCg==",
123 | },
124 | {
125 | "gzip compression - basic content",
126 | `data "cloudinit_config" "foo" {
127 | gzip = true
128 |
129 | part {
130 | content_type = "text/x-shellscript"
131 | content = "heythere"
132 | }
133 | }`,
134 | "H4sIAAAAAAAA/2TNuwrCQBCF4X5h32FJP0YrIWLhJYVFFEQFy1xGM5DMhtkJJG8vWkjQ8sDP+XaeFVnhMnaYuLZvlLpcNG5pwGrlCt9zlcu4jrJDlm5P1+N+c75H5r3ghhLIc+IWs7k11gBMI2u+35JzeKBAyqWviJ+JWxakk+CDKw4aDxBqbJpQCnVqTUYt/jk1jlqj4K8IYM0rAAD//0u6BO3QAAAA",
135 | },
136 | // Initial fix of panic when part block wasn't parsable
137 | // https://github.com/hashicorp/terraform/issues/13572
138 | //
139 | // Move to framework fixed parsing error, but introduced incorrect validation, empty content is valid
140 | // https://github.com/hashicorp/terraform-provider-cloudinit/issues/104
141 | {
142 | "empty content field in part block",
143 | `data "cloudinit_config" "foo" {
144 | part {
145 | content = ""
146 | }
147 | }`,
148 | "H4sIAAAAAAAA/3LOzytJzSvRDaksSLVSyC3NKcksSCwq0c/NrEhNsVZIyi/NS0ksqrRV8vX0dXXyD/VzcQyKVOIC8XTDUouKM/PzrBQM9Qx4uXi5dHWRFfFywc0uSswrTkst0nXNS85PycxLt1IwT8osQVIAtrwktaJEvyAnMTOPl8s3MzcVw3x0G3R1ebkAAQAA///dakG4wAAAAA==",
149 | },
150 | {
151 | "empty content field in one part block, multiple part blocks",
152 | `data "cloudinit_config" "foo" {
153 | gzip = false
154 | base64_encode = false
155 |
156 | part {
157 | content_type = "text/cloud-config"
158 | content = "abc"
159 | }
160 |
161 | part {
162 | content = ""
163 | }
164 |
165 | part {
166 | content_type = "text/cloud-config"
167 | content = ""
168 | }
169 | }`,
170 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/cloud-config\r\nMime-Version: 1.0\r\n\r\nabc\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain\r\nMime-Version: 1.0\r\n\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/cloud-config\r\nMime-Version: 1.0\r\n\r\n\r\n--MIMEBOUNDARY--\r\n",
171 | },
172 | }
173 |
174 | for _, tt := range testCases {
175 | t.Run(tt.Name, func(t *testing.T) {
176 | r.UnitTest(t, r.TestCase{
177 | ProtoV5ProviderFactories: testProtoV5ProviderFactories,
178 | Steps: []r.TestStep{
179 | {
180 | Config: tt.DataSourceBlock,
181 | Check: r.ComposeTestCheckFunc(
182 | r.TestCheckResourceAttr("data.cloudinit_config.foo", "rendered", tt.Expected),
183 | ),
184 | },
185 | },
186 | })
187 | })
188 | }
189 | }
190 |
191 | func TestConfigDataSourceRender_handleErrors(t *testing.T) {
192 | testCases := []struct {
193 | Name string
194 | DataSourceBlock string
195 | ErrorMatch *regexp.Regexp
196 | }{
197 | {
198 | "base64 can't be false when gzip is true",
199 | `data "cloudinit_config" "foo" {
200 | gzip = true
201 | base64_encode = false
202 |
203 | part {
204 | content = "abc"
205 | }
206 | }`,
207 | regexp.MustCompile("Expected base64_encode to be set to true when gzip is true"),
208 | },
209 | {
210 | "at least one part is required",
211 | `data "cloudinit_config" "foo" {
212 | gzip = false
213 | base64_encode = false
214 | }`,
215 | regexp.MustCompile("part must have a configuration value"),
216 | },
217 | }
218 |
219 | for _, tt := range testCases {
220 | t.Run(tt.Name, func(t *testing.T) {
221 | r.UnitTest(t, r.TestCase{
222 | ProtoV5ProviderFactories: testProtoV5ProviderFactories,
223 | Steps: []r.TestStep{
224 | {
225 | Config: tt.DataSourceBlock,
226 | ExpectError: tt.ErrorMatch,
227 | },
228 | },
229 | })
230 | })
231 | }
232 | }
233 |
234 | func TestConfigDataSource_UpgradeFromVersion2_2_0(t *testing.T) {
235 | testCases := []struct {
236 | Name string
237 | DataSourceBlock string
238 | Expected string
239 | }{
240 | {
241 | "multiple parts in cloudinit config",
242 | `data "cloudinit_config" "foo" {
243 | gzip = false
244 | base64_encode = false
245 |
246 | part {
247 | content_type = "text/x-shellscript"
248 | content = "foo1"
249 | filename = "foofile1.txt"
250 | merge_type = "list()+dict()+str()"
251 | }
252 |
253 | part {
254 | content = "bar1"
255 | filename = "barfile1.txt"
256 | merge_type = "list()+dict()+str()"
257 | }
258 | }`,
259 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"foofile1.txt\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\nX-Merge-Type: list()+dict()+str()\r\n\r\nfoo1\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"barfile1.txt\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain\r\nMime-Version: 1.0\r\nX-Merge-Type: list()+dict()+str()\r\n\r\nbar1\r\n--MIMEBOUNDARY--\r\n",
260 | },
261 | }
262 |
263 | for _, tt := range testCases {
264 | t.Run(tt.Name, func(t *testing.T) {
265 | r.UnitTest(t, r.TestCase{
266 | Steps: []r.TestStep{
267 | {
268 | ExternalProviders: map[string]r.ExternalProvider{
269 | "cloudinit": {
270 | VersionConstraint: "2.2.0",
271 | Source: "hashicorp/cloudinit",
272 | },
273 | },
274 | Config: tt.DataSourceBlock,
275 | Check: r.ComposeTestCheckFunc(
276 | r.TestCheckResourceAttr("data.cloudinit_config.foo", "rendered", tt.Expected),
277 | ),
278 | },
279 | {
280 | ProtoV5ProviderFactories: testProtoV5ProviderFactories,
281 | Config: tt.DataSourceBlock,
282 | Check: r.ComposeTestCheckFunc(
283 | r.TestCheckResourceAttr("data.cloudinit_config.foo", "rendered", tt.Expected),
284 | ),
285 | },
286 | },
287 | })
288 | })
289 | }
290 | }
291 |
292 | // This test ensures that unknown values are being handled properly in the `part` block
293 | // https://github.com/hashicorp/terraform-provider-cloudinit/issues/102
294 | func TestConfigDataSource_HandleUnknown(t *testing.T) {
295 | testCases := []struct {
296 | Name string
297 | DataSourceBlock string
298 | Expected string
299 | }{
300 | {
301 | "issue 102 - handle unknown in validate caused by variable",
302 | `
303 | variable "config_types" {
304 | default = ["text/cloud-config", "text/cloud-config"]
305 | }
306 |
307 | data "cloudinit_config" "foo" {
308 | gzip = true
309 | base64_encode = true
310 |
311 | dynamic "part" {
312 | for_each = var.config_types
313 | content {
314 | content_type = part.value
315 | content = <<-EOT
316 | #cloud-config
317 | test: ${part.value}
318 | EOT
319 | }
320 | }
321 | }
322 | `,
323 | "H4sIAAAAAAAA/3LOzytJzSvRDaksSLVSyC3NKcksSCwq0c/NrEhNsVZIyi/NS0ksqrRV8vX0dXXyD/VzcQyKVOIC8XTDUouKM/PzrBQM9Qx4uXi5dHWRFfFywc0uSswrTkst0nXNS85PycxLt1IwT8osQVIAtrwktaJEPzknvzRFNzk/Ly0znZfLNzM3FcMaZWQ1XCWpxSVY9A525+jq8nIBAgAA//821u5zfAEAAA==",
324 | },
325 | }
326 |
327 | for _, tt := range testCases {
328 | t.Run(tt.Name, func(t *testing.T) {
329 | r.UnitTest(t, r.TestCase{
330 | Steps: []r.TestStep{
331 | {
332 | ProtoV5ProviderFactories: testProtoV5ProviderFactories,
333 | Config: tt.DataSourceBlock,
334 | Check: r.ComposeTestCheckFunc(
335 | r.TestCheckResourceAttr("data.cloudinit_config.foo", "rendered", tt.Expected),
336 | ),
337 | },
338 | },
339 | })
340 | })
341 | }
342 | }
343 |
--------------------------------------------------------------------------------
/internal/provider/provider.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package provider
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/hashicorp/terraform-plugin-framework/datasource"
10 | "github.com/hashicorp/terraform-plugin-framework/provider"
11 | "github.com/hashicorp/terraform-plugin-framework/provider/schema"
12 | "github.com/hashicorp/terraform-plugin-framework/resource"
13 | )
14 |
15 | var (
16 | _ provider.Provider = (*cloudinitProvider)(nil)
17 | )
18 |
19 | type cloudinitProvider struct{}
20 |
21 | func New() provider.Provider {
22 | return &cloudinitProvider{}
23 | }
24 |
25 | func (p *cloudinitProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
26 | resp.TypeName = "cloudinit"
27 | }
28 |
29 | func (p *cloudinitProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
30 | resp.Schema = schema.Schema{
31 | MarkdownDescription: "The cloud-init Terraform provider exposes the `cloudinit_config` data source, previously available as the " +
32 | "`template_cloudinit_config` resource [in the template provider](https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/cloudinit_config), " +
33 | "which renders a [multipart MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) " +
34 | "for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).",
35 | }
36 | }
37 |
38 | func (p *cloudinitProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
39 | }
40 |
41 | func (p *cloudinitProvider) Resources(ctx context.Context) []func() resource.Resource {
42 | return []func() resource.Resource{
43 | func() resource.Resource {
44 | return &configResource{}
45 | },
46 | }
47 | }
48 |
49 | func (p *cloudinitProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
50 | return []func() datasource.DataSource{
51 | func() datasource.DataSource {
52 | return &configDataSource{}
53 | },
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/internal/provider/provider_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package provider
5 |
6 | import (
7 | "github.com/hashicorp/terraform-plugin-framework/providerserver"
8 | "github.com/hashicorp/terraform-plugin-go/tfprotov5"
9 | )
10 |
11 | var testProtoV5ProviderFactories = map[string]func() (tfprotov5.ProviderServer, error){
12 | "cloudinit": providerserver.NewProtocol5WithError(New()),
13 | }
14 |
--------------------------------------------------------------------------------
/internal/provider/resource_cloudinit_config.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package provider
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
10 | "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
11 | "github.com/hashicorp/terraform-plugin-framework/resource"
12 | "github.com/hashicorp/terraform-plugin-framework/resource/schema"
13 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
14 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
15 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
16 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
17 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
18 | "github.com/hashicorp/terraform-plugin-framework/schema/validator"
19 | )
20 |
21 | var (
22 | _ resource.ResourceWithValidateConfig = (*configResource)(nil)
23 | )
24 |
25 | type configResource struct{}
26 |
27 | func (r *configResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
28 | resp.TypeName = req.ProviderTypeName + "_config"
29 | }
30 |
31 | func (r *configResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
32 | var cloudinitConfig configModel
33 |
34 | resp.Diagnostics.Append(req.Config.Get(ctx, &cloudinitConfig)...)
35 | if resp.Diagnostics.HasError() {
36 | return
37 | }
38 |
39 | resp.Diagnostics.Append(cloudinitConfig.validate(ctx)...)
40 | }
41 |
42 | func (r *configResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
43 | resp.Schema = schema.Schema{
44 | Blocks: map[string]schema.Block{
45 | "part": schema.ListNestedBlock{
46 | Validators: []validator.List{
47 | listvalidator.IsRequired(),
48 | },
49 | NestedObject: schema.NestedBlockObject{
50 | Attributes: map[string]schema.Attribute{
51 | "content_type": schema.StringAttribute{
52 | Validators: []validator.String{
53 | stringvalidator.LengthAtLeast(1),
54 | },
55 | PlanModifiers: []planmodifier.String{
56 | stringplanmodifier.RequiresReplace(),
57 | },
58 | Optional: true,
59 | Computed: true,
60 | Default: stringdefault.StaticString("text/plain"),
61 | MarkdownDescription: "A MIME-style content type to report in the header for the part. Defaults to `text/plain`",
62 | },
63 | "content": schema.StringAttribute{
64 | PlanModifiers: []planmodifier.String{
65 | stringplanmodifier.RequiresReplace(),
66 | },
67 | Required: true,
68 | MarkdownDescription: "Body content for the part.",
69 | },
70 | "filename": schema.StringAttribute{
71 | PlanModifiers: []planmodifier.String{
72 | stringplanmodifier.RequiresReplace(),
73 | },
74 | Optional: true,
75 | MarkdownDescription: "A filename to report in the header for the part.",
76 | },
77 | "merge_type": schema.StringAttribute{
78 | PlanModifiers: []planmodifier.String{
79 | stringplanmodifier.RequiresReplace(),
80 | },
81 | Optional: true,
82 | MarkdownDescription: "A value for the `X-Merge-Type` header of the part, to control " +
83 | "[cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).",
84 | },
85 | },
86 | },
87 | MarkdownDescription: "A nested block type which adds a file to the generated cloud-init configuration. Use multiple " +
88 | "`part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document.",
89 | },
90 | },
91 | Attributes: map[string]schema.Attribute{
92 | "gzip": schema.BoolAttribute{
93 | PlanModifiers: []planmodifier.Bool{
94 | boolplanmodifier.RequiresReplace(),
95 | },
96 | Optional: true,
97 | Computed: true,
98 | Default: booldefault.StaticBool(true),
99 | MarkdownDescription: "Specify whether or not to gzip the `rendered` output. Defaults to `true`.",
100 | },
101 | "base64_encode": schema.BoolAttribute{
102 | PlanModifiers: []planmodifier.Bool{
103 | boolplanmodifier.RequiresReplace(),
104 | },
105 | Optional: true,
106 | Computed: true,
107 | Default: booldefault.StaticBool(true),
108 | MarkdownDescription: "Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.",
109 | },
110 | "boundary": schema.StringAttribute{
111 | Validators: []validator.String{
112 | stringvalidator.LengthAtLeast(1),
113 | },
114 | PlanModifiers: []planmodifier.String{
115 | stringplanmodifier.RequiresReplace(),
116 | },
117 | Optional: true,
118 | Computed: true,
119 | Default: stringdefault.StaticString("MIMEBOUNDARY"),
120 | MarkdownDescription: "Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.",
121 | },
122 | "rendered": schema.StringAttribute{
123 | Computed: true,
124 | MarkdownDescription: "The final rendered multi-part cloud-init config.",
125 | },
126 | "id": schema.StringAttribute{
127 | Computed: true,
128 | MarkdownDescription: "[CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.",
129 | },
130 | },
131 | DeprecationMessage: `This resource is deprecated, please use the cloudinit_config data source instead.`,
132 | MarkdownDescription: "Renders a [multi-part MIME configuration](https://cloudinit.readthedocs.io/en/latest/explanation/format.html#mime-multi-part-archive) " +
133 | "for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/).\n\n" +
134 | "Cloud-init is a commonly-used startup configuration utility for cloud compute instances. It accepts configuration via provider-specific " +
135 | "user data mechanisms, such as `user_data` for Amazon EC2 instances. Multi-part MIME is one of the data formats it accepts. For more information, " +
136 | "see [User-Data Formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) in the cloud-init manual.\n\n" +
137 | "This is not a generalized utility for producing multi-part MIME messages. Its feature set is specialized for cloud-init multi-part MIME messages.",
138 | }
139 | }
140 |
141 | func (r *configResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
142 | var cloudinitConfig configModel
143 |
144 | resp.Diagnostics.Append(req.Plan.Get(ctx, &cloudinitConfig)...)
145 | if resp.Diagnostics.HasError() {
146 | return
147 | }
148 |
149 | resp.Diagnostics.Append(cloudinitConfig.update(ctx)...)
150 | resp.Diagnostics.Append(resp.State.Set(ctx, cloudinitConfig)...)
151 | }
152 |
153 | func (r *configResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
154 | }
155 |
156 | func (r *configResource) Update(_ context.Context, _ resource.UpdateRequest, _ *resource.UpdateResponse) {
157 | }
158 |
159 | func (r *configResource) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {
160 | }
161 |
--------------------------------------------------------------------------------
/internal/provider/resource_cloudinit_config_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package provider
5 |
6 | import (
7 | "regexp"
8 | "testing"
9 |
10 | r "github.com/hashicorp/terraform-plugin-testing/helper/resource"
11 | )
12 |
13 | func TestConfigResourceRender(t *testing.T) {
14 | testCases := []struct {
15 | Name string
16 | ResourceBlock string
17 | Expected string
18 | }{
19 | {
20 | "no gzip or b64 - basic content",
21 | `resource "cloudinit_config" "foo" {
22 | gzip = false
23 | base64_encode = false
24 |
25 | part {
26 | content_type = "text/x-shellscript"
27 | content = "baz"
28 | }
29 | }`,
30 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n",
31 | },
32 | {
33 | "no gzip or b64 - basic content - default to text plain",
34 | `resource "cloudinit_config" "foo" {
35 | gzip = false
36 | base64_encode = false
37 |
38 | part {
39 | content = "baz"
40 | }
41 | }`,
42 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n",
43 | },
44 | {
45 | "no gzip or b64 - content with filename",
46 | `resource "cloudinit_config" "foo" {
47 | gzip = false
48 | base64_encode = false
49 |
50 | part {
51 | content_type = "text/x-shellscript"
52 | content = "baz"
53 | filename = "foobar.sh"
54 | }
55 | }`,
56 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"foobar.sh\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n",
57 | },
58 | {
59 | "no gzip or b64 - two parts, basic content",
60 | `resource "cloudinit_config" "foo" {
61 | gzip = false
62 | base64_encode = false
63 |
64 | part {
65 | content_type = "text/x-shellscript"
66 | content = "baz"
67 | }
68 | part {
69 | content_type = "text/x-shellscript"
70 | content = "ffbaz"
71 | }
72 | }`,
73 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nffbaz\r\n--MIMEBOUNDARY--\r\n",
74 | },
75 | {
76 | "no gzip or b64 - with boundary separator",
77 | `resource "cloudinit_config" "foo" {
78 | gzip = false
79 | base64_encode = false
80 | boundary = "//"
81 |
82 | part {
83 | content_type = "text/x-shellscript"
84 | content = "baz"
85 | }
86 | }`,
87 | "Content-Type: multipart/mixed; boundary=\"//\"\nMIME-Version: 1.0\r\n\r\n--//\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--//--\r\n",
88 | },
89 | {
90 | "no gzip or b64 - two parts - all fields",
91 | `resource "cloudinit_config" "foo" {
92 | gzip = false
93 | base64_encode = false
94 |
95 | part {
96 | content_type = "text/x-shellscript"
97 | content = "foo1"
98 | filename = "foofile1.txt"
99 | merge_type = "list()+dict()+str()"
100 | }
101 |
102 | part {
103 | content_type = "text/x-shellscript"
104 | content = "bar1"
105 | filename = "barfile1.txt"
106 | merge_type = "list()+dict()+str()"
107 | }
108 | }`,
109 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"foofile1.txt\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\nX-Merge-Type: list()+dict()+str()\r\n\r\nfoo1\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"barfile1.txt\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\nX-Merge-Type: list()+dict()+str()\r\n\r\nbar1\r\n--MIMEBOUNDARY--\r\n",
110 | },
111 | {
112 | "no gzip - b64 encoded - basic content",
113 | `resource "cloudinit_config" "foo" {
114 | gzip = false
115 | base64_encode = true
116 |
117 | part {
118 | content_type = "text/x-shellscript"
119 | content = "heythere"
120 | }
121 | }`,
122 | "Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSJNSU1FQk9VTkRBUlkiCk1JTUUtVmVyc2lvbjogMS4wDQoNCi0tTUlNRUJPVU5EQVJZDQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA3Yml0DQpDb250ZW50LVR5cGU6IHRleHQveC1zaGVsbHNjcmlwdA0KTWltZS1WZXJzaW9uOiAxLjANCg0KaGV5dGhlcmUNCi0tTUlNRUJPVU5EQVJZLS0NCg==",
123 | },
124 | {
125 | "gzip compression - basic content",
126 | `resource "cloudinit_config" "foo" {
127 | gzip = true
128 |
129 | part {
130 | content_type = "text/x-shellscript"
131 | content = "heythere"
132 | }
133 | }`,
134 | "H4sIAAAAAAAA/2TNuwrCQBCF4X5h32FJP0YrIWLhJYVFFEQFy1xGM5DMhtkJJG8vWkjQ8sDP+XaeFVnhMnaYuLZvlLpcNG5pwGrlCt9zlcu4jrJDlm5P1+N+c75H5r3ghhLIc+IWs7k11gBMI2u+35JzeKBAyqWviJ+JWxakk+CDKw4aDxBqbJpQCnVqTUYt/jk1jlqj4K8IYM0rAAD//0u6BO3QAAAA",
135 | },
136 | // Initial fix of panic when part block wasn't parsable
137 | // https://github.com/hashicorp/terraform/issues/13572
138 | //
139 | // Move to framework fixed parsing error, but introduced incorrect validation, empty content is valid
140 | // https://github.com/hashicorp/terraform-provider-cloudinit/issues/104
141 | {
142 | "empty content field in part block",
143 | `resource "cloudinit_config" "foo" {
144 | part {
145 | content = ""
146 | }
147 | }`,
148 | "H4sIAAAAAAAA/3LOzytJzSvRDaksSLVSyC3NKcksSCwq0c/NrEhNsVZIyi/NS0ksqrRV8vX0dXXyD/VzcQyKVOIC8XTDUouKM/PzrBQM9Qx4uXi5dHWRFfFywc0uSswrTkst0nXNS85PycxLt1IwT8osQVIAtrwktaJEvyAnMTOPl8s3MzcVw3x0G3R1ebkAAQAA///dakG4wAAAAA==",
149 | },
150 | {
151 | "empty content field in one part block, multiple part blocks",
152 | `resource "cloudinit_config" "foo" {
153 | gzip = false
154 | base64_encode = false
155 |
156 | part {
157 | content_type = "text/cloud-config"
158 | content = "abc"
159 | }
160 |
161 | part {
162 | content = ""
163 | }
164 |
165 | part {
166 | content_type = "text/cloud-config"
167 | content = ""
168 | }
169 | }`,
170 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/cloud-config\r\nMime-Version: 1.0\r\n\r\nabc\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain\r\nMime-Version: 1.0\r\n\r\n\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/cloud-config\r\nMime-Version: 1.0\r\n\r\n\r\n--MIMEBOUNDARY--\r\n",
171 | },
172 | }
173 |
174 | for _, tt := range testCases {
175 | t.Run(tt.Name, func(t *testing.T) {
176 | r.UnitTest(t, r.TestCase{
177 | ProtoV5ProviderFactories: testProtoV5ProviderFactories,
178 | Steps: []r.TestStep{
179 | {
180 | Config: tt.ResourceBlock,
181 | Check: r.ComposeTestCheckFunc(
182 | r.TestCheckResourceAttr("cloudinit_config.foo", "rendered", tt.Expected),
183 | ),
184 | },
185 | },
186 | })
187 | })
188 | }
189 | }
190 |
191 | func TestConfigResourceRender_handleErrors(t *testing.T) {
192 | testCases := []struct {
193 | Name string
194 | ResourceBlock string
195 | ErrorMatch *regexp.Regexp
196 | }{
197 | {
198 | "base64 can't be false when gzip is true",
199 | `resource "cloudinit_config" "foo" {
200 | gzip = true
201 | base64_encode = false
202 |
203 | part {
204 | content = "abc"
205 | }
206 | }`,
207 | regexp.MustCompile("Expected base64_encode to be set to true when gzip is true"),
208 | },
209 | {
210 | "at least one part is required",
211 | `resource "cloudinit_config" "foo" {
212 | gzip = false
213 | base64_encode = false
214 | }`,
215 | regexp.MustCompile("part must have a configuration value"),
216 | },
217 | }
218 |
219 | for _, tt := range testCases {
220 | t.Run(tt.Name, func(t *testing.T) {
221 | r.UnitTest(t, r.TestCase{
222 | ProtoV5ProviderFactories: testProtoV5ProviderFactories,
223 | Steps: []r.TestStep{
224 | {
225 | Config: tt.ResourceBlock,
226 | ExpectError: tt.ErrorMatch,
227 | },
228 | },
229 | })
230 | })
231 | }
232 | }
233 |
234 | func TestConfigResource_UpgradeFromVersion2_2_0(t *testing.T) {
235 | testCases := []struct {
236 | Name string
237 | ResourceBlock string
238 | Expected string
239 | }{
240 | {
241 | "multiple parts in cloudinit config",
242 | `resource "cloudinit_config" "foo" {
243 | gzip = false
244 | base64_encode = false
245 |
246 | part {
247 | content_type = "text/x-shellscript"
248 | content = "foo1"
249 | filename = "foofile1.txt"
250 | merge_type = "list()+dict()+str()"
251 | }
252 |
253 | part {
254 | content = "bar1"
255 | filename = "barfile1.txt"
256 | merge_type = "list()+dict()+str()"
257 | }
258 | }`,
259 | "Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"foofile1.txt\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\nX-Merge-Type: list()+dict()+str()\r\n\r\nfoo1\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"barfile1.txt\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain\r\nMime-Version: 1.0\r\nX-Merge-Type: list()+dict()+str()\r\n\r\nbar1\r\n--MIMEBOUNDARY--\r\n",
260 | },
261 | }
262 |
263 | for _, tt := range testCases {
264 | t.Run(tt.Name, func(t *testing.T) {
265 | r.UnitTest(t, r.TestCase{
266 | Steps: []r.TestStep{
267 | {
268 | ExternalProviders: map[string]r.ExternalProvider{
269 | "cloudinit": {
270 | VersionConstraint: "2.2.0",
271 | Source: "hashicorp/cloudinit",
272 | },
273 | },
274 | Config: tt.ResourceBlock,
275 | Check: r.ComposeTestCheckFunc(
276 | r.TestCheckResourceAttr("cloudinit_config.foo", "rendered", tt.Expected),
277 | ),
278 | },
279 | {
280 | ProtoV5ProviderFactories: testProtoV5ProviderFactories,
281 | Config: tt.ResourceBlock,
282 | Check: r.ComposeTestCheckFunc(
283 | r.TestCheckResourceAttr("cloudinit_config.foo", "rendered", tt.Expected),
284 | ),
285 | },
286 | },
287 | })
288 | })
289 | }
290 | }
291 |
292 | // This test ensures that unknown values are being handled properly in the `part` block
293 | // https://github.com/hashicorp/terraform-provider-cloudinit/issues/102
294 | func TestConfigResource_HandleUnknown(t *testing.T) {
295 | testCases := []struct {
296 | Name string
297 | ResourceBlock string
298 | Expected string
299 | }{
300 | {
301 | "issue 102 - handle unknown in validate caused by variable",
302 | `
303 | variable "config_types" {
304 | default = ["text/cloud-config", "text/cloud-config"]
305 | }
306 |
307 | resource "cloudinit_config" "foo" {
308 | gzip = true
309 | base64_encode = true
310 |
311 | dynamic "part" {
312 | for_each = var.config_types
313 | content {
314 | content_type = part.value
315 | content = <<-EOT
316 | #cloud-config
317 | test: ${part.value}
318 | EOT
319 | }
320 | }
321 | }
322 | `,
323 | "H4sIAAAAAAAA/3LOzytJzSvRDaksSLVSyC3NKcksSCwq0c/NrEhNsVZIyi/NS0ksqrRV8vX0dXXyD/VzcQyKVOIC8XTDUouKM/PzrBQM9Qx4uXi5dHWRFfFywc0uSswrTkst0nXNS85PycxLt1IwT8osQVIAtrwktaJEPzknvzRFNzk/Ly0znZfLNzM3FcMaZWQ1XCWpxSVY9A525+jq8nIBAgAA//821u5zfAEAAA==",
324 | },
325 | }
326 |
327 | for _, tt := range testCases {
328 | t.Run(tt.Name, func(t *testing.T) {
329 | r.UnitTest(t, r.TestCase{
330 | Steps: []r.TestStep{
331 | {
332 | ProtoV5ProviderFactories: testProtoV5ProviderFactories,
333 | Config: tt.ResourceBlock,
334 | Check: r.ComposeTestCheckFunc(
335 | r.TestCheckResourceAttr("cloudinit_config.foo", "rendered", tt.Expected),
336 | ),
337 | },
338 | },
339 | })
340 | })
341 | }
342 | }
343 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | package main
5 |
6 | import (
7 | "context"
8 | "flag"
9 | "log"
10 |
11 | "github.com/hashicorp/terraform-plugin-framework/providerserver"
12 |
13 | "github.com/hashicorp/terraform-provider-cloudinit/internal/provider"
14 | )
15 |
16 | func main() {
17 | var debug bool
18 |
19 | flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
20 | flag.Parse()
21 |
22 | err := providerserver.Serve(context.Background(), provider.New, providerserver.ServeOpts{
23 | Address: "registry.terraform.io/hashicorp/cloudinit",
24 | Debug: debug,
25 | ProtocolVersion: 5,
26 | })
27 | if err != nil {
28 | log.Fatal(err)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/templates/data-sources/config.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
3 | description: |-
4 | {{ .Description | plainmarkdown | trimspace | prefixlines " " }}
5 | ---
6 |
7 | # {{.Name}} ({{.Type}})
8 |
9 | {{ .Description }}
10 |
11 | ## Example Usage
12 |
13 | ### Config
14 | {{ tffile "examples/data-sources/cloudinit_config/data-source.tf" }}
15 |
16 | ### hello-script.sh
17 | {{ codefile "shell" "examples/data-sources/cloudinit_config/hello-script.sh" }}
18 |
19 | ### cloud-config.yaml
20 | {{ codefile "yaml" "examples/data-sources/cloudinit_config/cloud-config.yaml" }}
21 |
22 |
23 |
24 | ## Schema
25 |
26 | ### Required
27 |
28 | - `part` (Block List) A nested block type which adds a file to the generated cloud-init configuration. Use multiple `part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document. (see [below for nested schema](#nestedblock--part))
29 |
30 | ### Optional
31 |
32 | - `base64_encode` (Boolean) Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.
33 | - `boundary` (String) Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.
34 | - `gzip` (Boolean) Specify whether or not to gzip the `rendered` output. Defaults to `true`.
35 |
36 | ### Read-Only
37 |
38 | - `id` (String) [CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.
39 | - `rendered` (String) The final rendered multi-part cloud-init config.
40 |
41 |
42 | ### Nested Schema for `part`
43 |
44 | Required:
45 |
46 | - `content` (String) Body content for the part.
47 |
48 | Optional:
49 |
50 | - `content_type` (String) A MIME-style content type to report in the header for the part. Defaults to `text/plain`
51 | - `filename` (String) A filename to report in the header for the part.
52 | - `merge_type` (String) A value for the `X-Merge-Type` header of the part, to control [cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).
53 |
--------------------------------------------------------------------------------
/templates/index.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "{{ .ProviderShortName }} Provider"
3 | description: |-
4 | {{ .Description | plainmarkdown }}
5 | ---
6 |
7 | # {{ .ProviderShortName }} Provider
8 |
9 | {{ .Description }}
10 |
11 | This provider requires no configuration. For information on the resources it provides, see the navigation bar.
12 |
13 | {{- /* No schema in this provider, so no need for this: .SchemaMarkdown | trimspace */ -}}
--------------------------------------------------------------------------------
/templates/resources/config.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
3 | description: |-
4 | {{ .Description | plainmarkdown | trimspace | prefixlines " " }}
5 | ---
6 |
7 | # {{.Name}} ({{.Type}})
8 |
9 | ~> **This resource is deprecated** Please use the [cloudinit_config](https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs/data-sources/config)
10 | data source instead.
11 |
12 | {{ .Description }}
13 |
14 | ## Example Usage
15 |
16 | ### Config
17 | {{ tffile "examples/resources/cloudinit_config/resource.tf" }}
18 |
19 | ### hello-script.sh
20 | {{ codefile "shell" "examples/resources/cloudinit_config/hello-script.sh" }}
21 |
22 | ### cloud-config.yaml
23 | {{ codefile "yaml" "examples/resources/cloudinit_config/cloud-config.yaml" }}
24 |
25 |
26 |
27 | ## Schema
28 |
29 | ### Required
30 |
31 | - `part` (Block List) A nested block type which adds a file to the generated cloud-init configuration. Use multiple `part` blocks to specify multiple files, which will be included in order of declaration in the final MIME document. (see [below for nested schema](#nestedblock--part))
32 |
33 | ### Optional
34 |
35 | - `base64_encode` (Boolean) Specify whether or not to base64 encode the `rendered` output. Defaults to `true`, and cannot be disabled if gzip is `true`.
36 | - `boundary` (String) Specify the Writer's default boundary separator. Defaults to `MIMEBOUNDARY`.
37 | - `gzip` (Boolean) Specify whether or not to gzip the `rendered` output. Defaults to `true`.
38 |
39 | ### Read-Only
40 |
41 | - `id` (String) [CRC-32](https://pkg.go.dev/hash/crc32) checksum of `rendered` cloud-init config.
42 | - `rendered` (String) The final rendered multi-part cloud-init config.
43 |
44 |
45 | ### Nested Schema for `part`
46 |
47 | Required:
48 |
49 | - `content` (String) Body content for the part.
50 |
51 | Optional:
52 |
53 | - `content_type` (String) A MIME-style content type to report in the header for the part. Defaults to `text/plain`
54 | - `filename` (String) A filename to report in the header for the part.
55 | - `merge_type` (String) A value for the `X-Merge-Type` header of the part, to control [cloud-init merging behavior](https://cloudinit.readthedocs.io/en/latest/reference/merging.html).
56 |
--------------------------------------------------------------------------------
/terraform-registry-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "metadata": {
4 | "protocol_versions": ["5.0"]
5 | }
6 | }
--------------------------------------------------------------------------------
/tools/go.mod:
--------------------------------------------------------------------------------
1 | module tools
2 |
3 | go 1.23.7
4 |
5 | require (
6 | github.com/hashicorp/copywrite v0.22.0
7 | github.com/hashicorp/terraform-plugin-docs v0.21.0
8 | )
9 |
10 | require (
11 | dario.cat/mergo v1.0.1 // indirect
12 | github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
13 | github.com/BurntSushi/toml v1.2.1 // indirect
14 | github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
15 | github.com/Masterminds/goutils v1.1.1 // indirect
16 | github.com/Masterminds/semver/v3 v3.3.0 // indirect
17 | github.com/Masterminds/sprig/v3 v3.3.0 // indirect
18 | github.com/ProtonMail/go-crypto v1.1.3 // indirect
19 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
20 | github.com/armon/go-radix v1.0.0 // indirect
21 | github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
22 | github.com/bgentry/speakeasy v0.1.0 // indirect
23 | github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
24 | github.com/bradleyfalzon/ghinstallation/v2 v2.5.0 // indirect
25 | github.com/cli/go-gh/v2 v2.12.1 // indirect
26 | github.com/cli/safeexec v1.0.0 // indirect
27 | github.com/cloudflare/circl v1.6.1 // indirect
28 | github.com/fatih/color v1.16.0 // indirect
29 | github.com/fsnotify/fsnotify v1.5.4 // indirect
30 | github.com/go-openapi/errors v0.20.2 // indirect
31 | github.com/go-openapi/strfmt v0.21.3 // indirect
32 | github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
33 | github.com/golang/protobuf v1.5.2 // indirect
34 | github.com/google/go-github/v45 v45.2.0 // indirect
35 | github.com/google/go-github/v53 v53.0.0 // indirect
36 | github.com/google/go-querystring v1.1.0 // indirect
37 | github.com/google/uuid v1.6.0 // indirect
38 | github.com/hashicorp/cli v1.1.7 // indirect
39 | github.com/hashicorp/errwrap v1.1.0 // indirect
40 | github.com/hashicorp/go-checkpoint v0.5.0 // indirect
41 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
42 | github.com/hashicorp/go-hclog v1.6.3 // indirect
43 | github.com/hashicorp/go-multierror v1.1.1 // indirect
44 | github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
45 | github.com/hashicorp/go-uuid v1.0.3 // indirect
46 | github.com/hashicorp/go-version v1.7.0 // indirect
47 | github.com/hashicorp/hc-install v0.9.1 // indirect
48 | github.com/hashicorp/hcl v1.0.0 // indirect
49 | github.com/hashicorp/terraform-exec v0.22.0 // indirect
50 | github.com/hashicorp/terraform-json v0.24.0 // indirect
51 | github.com/huandu/xstrings v1.5.0 // indirect
52 | github.com/inconshreveable/mousetrap v1.0.1 // indirect
53 | github.com/jedib0t/go-pretty v4.3.0+incompatible // indirect
54 | github.com/jedib0t/go-pretty/v6 v6.4.6 // indirect
55 | github.com/joho/godotenv v1.3.0 // indirect
56 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
57 | github.com/knadh/koanf v1.5.0 // indirect
58 | github.com/mattn/go-colorable v0.1.14 // indirect
59 | github.com/mattn/go-isatty v0.0.20 // indirect
60 | github.com/mattn/go-runewidth v0.0.16 // indirect
61 | github.com/mergestat/timediff v0.0.3 // indirect
62 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
63 | github.com/mitchellh/copystructure v1.2.0 // indirect
64 | github.com/mitchellh/go-homedir v1.1.0 // indirect
65 | github.com/mitchellh/mapstructure v1.5.0 // indirect
66 | github.com/mitchellh/reflectwalk v1.0.2 // indirect
67 | github.com/oklog/ulid v1.3.1 // indirect
68 | github.com/posener/complete v1.2.3 // indirect
69 | github.com/rivo/uniseg v0.4.7 // indirect
70 | github.com/samber/lo v1.37.0 // indirect
71 | github.com/shopspring/decimal v1.4.0 // indirect
72 | github.com/spf13/cast v1.7.0 // indirect
73 | github.com/spf13/cobra v1.6.1 // indirect
74 | github.com/spf13/pflag v1.0.5 // indirect
75 | github.com/thanhpk/randstr v1.0.4 // indirect
76 | github.com/yuin/goldmark v1.7.8 // indirect
77 | github.com/yuin/goldmark-meta v1.1.0 // indirect
78 | github.com/zclconf/go-cty v1.16.2 // indirect
79 | go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
80 | go.mongodb.org/mongo-driver v1.10.0 // indirect
81 | golang.org/x/crypto v0.36.0 // indirect
82 | golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
83 | golang.org/x/mod v0.22.0 // indirect
84 | golang.org/x/net v0.38.0 // indirect
85 | golang.org/x/oauth2 v0.8.0 // indirect
86 | golang.org/x/sync v0.12.0 // indirect
87 | golang.org/x/sys v0.31.0 // indirect
88 | golang.org/x/term v0.30.0 // indirect
89 | golang.org/x/text v0.23.0 // indirect
90 | google.golang.org/appengine v1.6.7 // indirect
91 | google.golang.org/protobuf v1.33.0 // indirect
92 | gopkg.in/yaml.v2 v2.4.0 // indirect
93 | gopkg.in/yaml.v3 v3.0.1 // indirect
94 | )
95 |
--------------------------------------------------------------------------------
/tools/tools.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) HashiCorp, Inc.
2 | // SPDX-License-Identifier: MPL-2.0
3 |
4 | //go:build generate
5 |
6 | package tools
7 |
8 | import (
9 | // document generation
10 | _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
11 | // copywrite header generation
12 | _ "github.com/hashicorp/copywrite"
13 | )
14 |
15 | // Generate copyright headers
16 | //go:generate go run github.com/hashicorp/copywrite headers -d .. --config ../.copywrite.hcl
17 | // Format Terraform code for use in documentation.
18 | // If you do not have Terraform installed, you can remove the formatting command, but it is suggested
19 | // to ensure the documentation is formatted properly.
20 | //go:generate terraform fmt -recursive ../examples/
21 | // Generate documentation.
22 | //go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate --provider-dir ..
23 |
--------------------------------------------------------------------------------
/version/VERSION:
--------------------------------------------------------------------------------
1 | 2.3.7
2 |
--------------------------------------------------------------------------------