[Terraform] New Terraform Provider generator (#22949)

* [new] Add Terraform provider generator

Add a new experimental code generator that produces HashiCorp Terraform
providers from OpenAPI specifications using the Plugin Framework SDK.

The generator (terraform-provider) supports:
- CRUD operation detection from REST patterns and vendor extensions
- Resource, data source, and model generation per API tag
- HTTP client with API key, bearer token, and basic auth
- Type mapping from OpenAPI/Go types to Terraform schema types
- Import state support
- Configurable provider name, registry address, and version

Includes mustache templates for: provider, resources, data sources,
models, client, go.mod, GNUmakefile, README, and example configs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [new] Add Terraform provider petstore sample and acceptance tests

Add sample generation config and generated Terraform provider for the
petstore OpenAPI spec, along with Go acceptance tests that exercise
the provider lifecycle (create, read, update, delete, import).

Generated output includes:
- Provider with auth configuration (API key, bearer, basic)
- Pet, User, and Store resources and data sources
- Client package with HTTP client and model structs
- Go acceptance tests using terraform-plugin-testing
- Example Terraform configurations for each resource/data source

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: docs

* terraform: add more sample tests and ci workflow

* ci: get ci passing

* ci: fixes

* chore: docs

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason D'Amour
2026-02-13 23:02:42 -08:00
committed by GitHub
parent fffc21e3ee
commit 2a2e470165
160 changed files with 7628 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
name: Samples Terraform
on:
push:
paths:
- 'samples/client/petstore/terraform/**'
- 'samples/client/petstore/terraform-addpet/**'
- 'samples/client/petstore/terraform-server/**'
- 'samples/client/others/terraform/**'
pull_request:
paths:
- 'samples/client/petstore/terraform/**'
- 'samples/client/petstore/terraform-addpet/**'
- 'samples/client/petstore/terraform-server/**'
- 'samples/client/others/terraform/**'
jobs:
build:
name: Build Terraform Provider
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sample:
- samples/client/petstore/terraform/
- samples/client/petstore/terraform-addpet/
- samples/client/petstore/terraform-server/
- samples/client/others/terraform/allof-discriminator/
- samples/client/others/terraform/oneof-anyof-required/
- samples/client/others/terraform/oneof-discriminator-lookup/
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with:
go-version: "stable"
- run: go version
- name: Install Dependencies
working-directory: ${{ matrix.sample }}
run: |
go mod tidy
- name: Build provider
working-directory: ${{ matrix.sample }}
run: go build -v ./...
- name: Run tests
working-directory: ${{ matrix.sample }}
run: go test ./... -v -timeout 120m

View File

@@ -0,0 +1,11 @@
generatorName: terraform-provider
outputDir: samples/client/others/terraform/allof-discriminator
inputSpec: modules/openapi-generator/src/test/resources/3_0/go/allof_multiple_ref_and_discriminator.yaml
templateDir: modules/openapi-generator/src/main/resources/terraform-provider
gitHost: github.com
gitUserId: example
gitRepoId: terraform-provider-allof
additionalProperties:
providerName: "allof"
providerAddress: "registry.terraform.io/example/allof"
hideGenerationTimestamp: "true"

View File

@@ -0,0 +1,11 @@
generatorName: terraform-provider
outputDir: samples/client/others/terraform/oneof-anyof-required
inputSpec: modules/openapi-generator/src/test/resources/3_0/go/spec-with-oneof-anyof-required.yaml
templateDir: modules/openapi-generator/src/main/resources/terraform-provider
gitHost: github.com
gitUserId: example
gitRepoId: terraform-provider-oneof-anyof
additionalProperties:
providerName: "oneof"
providerAddress: "registry.terraform.io/example/oneof-anyof"
hideGenerationTimestamp: "true"

View File

@@ -0,0 +1,11 @@
generatorName: terraform-provider
outputDir: samples/client/others/terraform/oneof-discriminator-lookup
inputSpec: modules/openapi-generator/src/test/resources/3_0/go/spec-with-oneof-discriminator.yaml
templateDir: modules/openapi-generator/src/main/resources/terraform-provider
gitHost: github.com
gitUserId: example
gitRepoId: terraform-provider-oneof-disc
additionalProperties:
providerName: "oneof"
providerAddress: "registry.terraform.io/example/oneof-disc"
hideGenerationTimestamp: "true"

View File

@@ -0,0 +1,11 @@
generatorName: terraform-provider
outputDir: samples/client/petstore/terraform-addpet
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-addpet-only.yaml
templateDir: modules/openapi-generator/src/main/resources/terraform-provider
gitHost: github.com
gitUserId: example
gitRepoId: terraform-provider-petstore-addpet
additionalProperties:
providerName: "petstore"
providerAddress: "registry.terraform.io/example/petstore-addpet"
hideGenerationTimestamp: "true"

View File

@@ -0,0 +1,11 @@
generatorName: terraform-provider
outputDir: samples/client/petstore/terraform
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/terraform-provider
gitHost: github.com
gitUserId: example
gitRepoId: terraform-provider-petstore
additionalProperties:
providerName: "petstore"
providerAddress: "registry.terraform.io/example/petstore"
hideGenerationTimestamp: "true"

View File

@@ -0,0 +1,11 @@
generatorName: terraform-provider
outputDir: samples/client/petstore/terraform-server
inputSpec: modules/openapi-generator/src/test/resources/3_0/go-server/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/terraform-provider
gitHost: github.com
gitUserId: example
gitRepoId: terraform-provider-petstore-server
additionalProperties:
providerName: "petstore"
providerAddress: "registry.terraform.io/example/petstore-server"
hideGenerationTimestamp: "true"

View File

@@ -70,6 +70,7 @@ The following generators are available:
* [swift-combine](generators/swift-combine.md)
* [swift5 (deprecated)](generators/swift5.md)
* [swift6](generators/swift6.md)
* [terraform-provider (experimental)](generators/terraform-provider.md)
* [typescript (experimental)](generators/typescript.md)
* [typescript-angular](generators/typescript-angular.md)
* [typescript-aurelia](generators/typescript-aurelia.md)

View File

@@ -0,0 +1,229 @@
---
title: Documentation for the terraform-provider Generator
---
## METADATA
| Property | Value | Notes |
| -------- | ----- | ----- |
| generator name | terraform-provider | pass this to the generate command after -g |
| generator stability | EXPERIMENTAL | |
| generator type | CLIENT | |
| generator language | Go | |
| generator default templating engine | mustache | |
| helpTxt | Generates a Terraform provider (Go, using HashiCorp Plugin Framework). | |
## CONFIG OPTIONS
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
|packageName|Go package name (convention: lowercase).| |openapi|
|packageVersion|Go package version.| |1.0.0|
|providerAddress|Terraform provider registry address| |registry.terraform.io/example/example|
|providerName|Terraform provider name (e.g. 'petstore')| |example|
|providerVersion|Terraform provider version| |0.1.0|
## IMPORT MAPPING
| Type/Alias | Imports |
| ---------- | ------- |
## INSTANTIATION TYPES
| Type/Alias | Instantiated By |
| ---------- | --------------- |
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>bool</li>
<li>byte</li>
<li>complex128</li>
<li>complex64</li>
<li>float32</li>
<li>float64</li>
<li>int</li>
<li>int32</li>
<li>int64</li>
<li>interface{}</li>
<li>map[string]interface{}</li>
<li>rune</li>
<li>string</li>
<li>uint</li>
<li>uint32</li>
<li>uint64</li>
</ul>
## RESERVED WORDS
<ul class="column-ul">
<li>bool</li>
<li>break</li>
<li>byte</li>
<li>case</li>
<li>chan</li>
<li>complex128</li>
<li>complex64</li>
<li>const</li>
<li>continue</li>
<li>default</li>
<li>defer</li>
<li>else</li>
<li>error</li>
<li>fallthrough</li>
<li>float32</li>
<li>float64</li>
<li>for</li>
<li>func</li>
<li>go</li>
<li>goto</li>
<li>if</li>
<li>import</li>
<li>int</li>
<li>int16</li>
<li>int32</li>
<li>int64</li>
<li>int8</li>
<li>interface</li>
<li>map</li>
<li>nil</li>
<li>package</li>
<li>range</li>
<li>return</li>
<li>rune</li>
<li>select</li>
<li>string</li>
<li>struct</li>
<li>switch</li>
<li>type</li>
<li>uint</li>
<li>uint16</li>
<li>uint32</li>
<li>uint64</li>
<li>uint8</li>
<li>uintptr</li>
<li>var</li>
</ul>
## FEATURE SET
### Client Modification Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasePath|✗|ToolingExtension
|Authorizations|✗|ToolingExtension
|UserAgent|✗|ToolingExtension
|MockServer|✗|ToolingExtension
### Data Type Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Custom|✗|OAS2,OAS3
|Int32|✓|OAS2,OAS3
|Int64|✓|OAS2,OAS3
|Float|✓|OAS2,OAS3
|Double|✓|OAS2,OAS3
|Decimal|✓|ToolingExtension
|String|✓|OAS2,OAS3
|Byte|✓|OAS2,OAS3
|Binary|✓|OAS2,OAS3
|Boolean|✓|OAS2,OAS3
|Date|✓|OAS2,OAS3
|DateTime|✓|OAS2,OAS3
|Password|✓|OAS2,OAS3
|File|✓|OAS2
|Uuid|✗|
|Array|✓|OAS2,OAS3
|Null|✗|OAS3
|AnyType|✗|OAS2,OAS3
|Object|✓|OAS2,OAS3
|Maps|✓|ToolingExtension
|CollectionFormat|✓|OAS2
|CollectionFormatMulti|✓|OAS2
|Enum|✓|OAS2,OAS3
|ArrayOfEnum|✓|ToolingExtension
|ArrayOfModel|✓|ToolingExtension
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
|ArrayOfCollectionOfModel|✓|ToolingExtension
|ArrayOfCollectionOfEnum|✓|ToolingExtension
|MapOfEnum|✓|ToolingExtension
|MapOfModel|✓|ToolingExtension
|MapOfCollectionOfPrimitives|✓|ToolingExtension
|MapOfCollectionOfModel|✓|ToolingExtension
|MapOfCollectionOfEnum|✓|ToolingExtension
### Documentation Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Readme|✓|ToolingExtension
|Model|✓|ToolingExtension
|Api|✓|ToolingExtension
### Global Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Host|✓|OAS2,OAS3
|BasePath|✓|OAS2,OAS3
|Info|✓|OAS2,OAS3
|Schemes|✗|OAS2,OAS3
|PartialSchemes|✓|OAS2,OAS3
|Consumes|✓|OAS2
|Produces|✓|OAS2
|ExternalDocumentation|✓|OAS2,OAS3
|Examples|✓|OAS2,OAS3
|XMLStructureDefinitions|✗|OAS2,OAS3
|MultiServer|✗|OAS3
|ParameterizedServer|✗|OAS3
|ParameterStyling|✗|OAS3
|Callbacks|✗|OAS3
|LinkObjects|✗|OAS3
### Parameter Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Path|✓|OAS2,OAS3
|Query|✓|OAS2,OAS3
|Header|✓|OAS2,OAS3
|Body|✓|OAS2
|FormUnencoded|✓|OAS2
|FormMultipart|✓|OAS2
|Cookie|✓|OAS3
### Schema Support Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Simple|✓|OAS2,OAS3
|Composite|✓|OAS2,OAS3
|Polymorphism|✗|OAS2,OAS3
|Union|✗|OAS3
|allOf|✗|OAS2,OAS3
|anyOf|✗|OAS3
|oneOf|✗|OAS3
|not|✗|OAS3
### Security Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasicAuth|✓|OAS2,OAS3
|ApiKey|✓|OAS2,OAS3
|OpenIDConnect|✗|OAS3
|BearerToken|✓|OAS3
|OAuth2_Implicit|✗|OAS2,OAS3
|OAuth2_Password|✗|OAS2,OAS3
|OAuth2_ClientCredentials|✗|OAS2,OAS3
|OAuth2_AuthorizationCode|✗|OAS2,OAS3
|SignatureAuth|✗|OAS3
|AWSV4Signature|✗|ToolingExtension
### Wire Format Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|JSON|✓|OAS2,OAS3
|XML|✗|OAS2,OAS3
|PROTOBUF|✗|ToolingExtension
|Custom|✗|OAS2,OAS3

View File

@@ -0,0 +1,556 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.languages;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.openapitools.codegen.model.OperationMap;
import org.openapitools.codegen.model.OperationsMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import static org.openapitools.codegen.utils.StringUtils.camelize;
import static org.openapitools.codegen.utils.StringUtils.underscore;
public class TerraformProviderCodegen extends AbstractGoCodegen {
private final Logger LOGGER = LoggerFactory.getLogger(TerraformProviderCodegen.class);
public static final String PROVIDER_NAME = "providerName";
public static final String PROVIDER_ADDRESS = "providerAddress";
public static final String PROVIDER_VERSION = "providerVersion";
protected String providerName = "example";
protected String providerAddress = "registry.terraform.io/example/example";
protected String providerVersion = "0.1.0";
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public String getName() {
return "terraform-provider";
}
@Override
public String getHelp() {
return "Generates a Terraform provider (Go, using HashiCorp Plugin Framework).";
}
public TerraformProviderCodegen() {
super();
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
.stability(Stability.EXPERIMENTAL)
.build();
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON))
.securityFeatures(EnumSet.of(
SecurityFeature.BasicAuth,
SecurityFeature.BearerToken,
SecurityFeature.ApiKey
))
.excludeGlobalFeatures(
GlobalFeature.XMLStructureDefinitions,
GlobalFeature.Callbacks,
GlobalFeature.LinkObjects,
GlobalFeature.ParameterStyling
)
.excludeSchemaSupportFeatures(
SchemaSupportFeature.Polymorphism
)
);
outputFolder = "generated-code/terraform-provider";
embeddedTemplateDir = templateDir = "terraform-provider";
// API templates: generate per-tag resource, data source, and model files
apiTemplateFiles.put("resource.mustache", "_resource.go");
apiTemplateFiles.put("data_source.mustache", "_data_source.go");
apiTemplateFiles.put("resource_model.mustache", "_model.go");
// Model templates: generate per-schema Go structs for the client package
modelTemplateFiles.put("model.mustache", ".go");
// No doc templates
apiDocTemplateFiles.clear();
modelDocTemplateFiles.clear();
hideGenerationTimestamp = Boolean.TRUE;
// Override type mappings for Terraform (no time.Time or *os.File)
typeMapping.put("DateTime", "string");
typeMapping.put("date", "string");
typeMapping.put("File", "string");
typeMapping.put("file", "string");
typeMapping.put("binary", "string");
cliOptions.add(new CliOption(PROVIDER_NAME, "Terraform provider name (e.g. 'petstore')")
.defaultValue(providerName));
cliOptions.add(new CliOption(PROVIDER_ADDRESS, "Terraform provider registry address")
.defaultValue(providerAddress));
cliOptions.add(new CliOption(PROVIDER_VERSION, "Terraform provider version")
.defaultValue(providerVersion));
}
@Override
public void processOpts() {
super.processOpts();
if (additionalProperties.containsKey(PROVIDER_NAME)) {
providerName = additionalProperties.get(PROVIDER_NAME).toString();
}
additionalProperties.put(PROVIDER_NAME, providerName);
if (additionalProperties.containsKey(PROVIDER_ADDRESS)) {
providerAddress = additionalProperties.get(PROVIDER_ADDRESS).toString();
}
additionalProperties.put(PROVIDER_ADDRESS, providerAddress);
if (additionalProperties.containsKey(PROVIDER_VERSION)) {
providerVersion = additionalProperties.get(PROVIDER_VERSION).toString();
}
additionalProperties.put(PROVIDER_VERSION, providerVersion);
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
} else {
setPackageName("provider");
}
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
apiPackage = "internal" + File.separator + "provider";
modelPackage = "internal" + File.separator + "client";
// Supporting files
supportingFiles.add(new SupportingFile("main.mustache", "", "main.go"));
supportingFiles.add(new SupportingFile("provider.mustache", "internal" + File.separator + "provider", "provider.go"));
supportingFiles.add(new SupportingFile("client.mustache", "internal" + File.separator + "client", "client.go"));
supportingFiles.add(new SupportingFile("go.mod.mustache", "", "go.mod"));
supportingFiles.add(new SupportingFile("GNUmakefile.mustache", "", "GNUmakefile"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
supportingFiles.add(new SupportingFile("provider_example.mustache", "examples" + File.separator + "provider", "provider.tf"));
}
@Override
public String apiFileFolder() {
return outputFolder + File.separator + "internal" + File.separator + "provider";
}
@Override
public String modelFileFolder() {
return outputFolder + File.separator + "internal" + File.separator + "client";
}
@Override
public String toApiFilename(String name) {
return underscore(name);
}
@Override
public String toModelFilename(String name) {
return "model_" + underscore(name);
}
@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
OperationMap objectMap = objs.getOperations();
List<CodegenOperation> operations = objectMap.getOperation();
// Store original uppercase HTTP method and build fmt.Sprintf-ready paths
for (CodegenOperation operation : operations) {
// Store uppercase method for net/http (e.g. "POST", "GET")
operation.vendorExtensions.put("x-terraform-http-method", operation.httpMethod.toUpperCase(Locale.ROOT));
// Convert path params to fmt.Sprintf format: /pet/{petId} -> /pet/%v
if (operation.path != null && operation.pathParams != null && !operation.pathParams.isEmpty()) {
String fmtPath = operation.path;
for (CodegenParameter param : operation.pathParams) {
fmtPath = fmtPath.replace("{" + param.baseName + "}", "%v");
}
operation.vendorExtensions.put("x-terraform-path-fmt", fmtPath);
}
// http method verb conversion (e.g. PUT => Put) as parent does
operation.httpMethod = camelize(operation.httpMethod.toLowerCase(Locale.ROOT));
}
// CRUD detection per tag
CodegenOperation createOp = null;
CodegenOperation readOp = null;
CodegenOperation updateOp = null;
CodegenOperation deleteOp = null;
CodegenOperation listOp = null;
// First pass: check for explicit vendor extensions
for (CodegenOperation op : operations) {
if (getBooleanVendorExtension(op, "x-terraform-exclude")) {
continue;
}
if (getBooleanVendorExtension(op, "x-terraform-is-create") && createOp == null) {
createOp = op;
}
if (getBooleanVendorExtension(op, "x-terraform-is-read") && readOp == null) {
readOp = op;
}
if (getBooleanVendorExtension(op, "x-terraform-is-update") && updateOp == null) {
updateOp = op;
}
if (getBooleanVendorExtension(op, "x-terraform-is-delete") && deleteOp == null) {
deleteOp = op;
}
if (getBooleanVendorExtension(op, "x-terraform-is-list") && listOp == null) {
listOp = op;
}
}
// Second pass: auto-detect using REST pattern methods
for (CodegenOperation op : operations) {
if (getBooleanVendorExtension(op, "x-terraform-exclude")) {
continue;
}
if (createOp == null && op.isRestfulCreate()) {
createOp = op;
} else if (readOp == null && op.isRestfulShow()) {
readOp = op;
} else if (updateOp == null && op.isRestfulUpdate()) {
updateOp = op;
} else if (deleteOp == null && op.isRestfulDestroy()) {
deleteOp = op;
} else if (listOp == null && op.isRestfulIndex()) {
listOp = op;
}
}
// Mark the selected operations with vendor extensions
if (createOp != null) {
createOp.vendorExtensions.put("x-terraform-is-create", true);
}
if (readOp != null) {
readOp.vendorExtensions.put("x-terraform-is-read", true);
}
if (updateOp != null) {
updateOp.vendorExtensions.put("x-terraform-is-update", true);
}
if (deleteOp != null) {
deleteOp.vendorExtensions.put("x-terraform-is-delete", true);
}
if (listOp != null) {
listOp.vendorExtensions.put("x-terraform-is-list", true);
}
// Tag-level flags and CRUD details for template rendering
objectMap.put("hasCreate", createOp != null);
objectMap.put("hasRead", readOp != null);
objectMap.put("hasUpdate", updateOp != null);
objectMap.put("hasDelete", deleteOp != null);
objectMap.put("hasList", listOp != null);
// Store CRUD operation details at tag level for simplified template access
if (createOp != null) {
objectMap.put("createMethod", createOp.vendorExtensions.get("x-terraform-http-method"));
objectMap.put("createPath", createOp.path);
}
if (readOp != null) {
objectMap.put("readMethod", readOp.vendorExtensions.get("x-terraform-http-method"));
objectMap.put("readPath", readOp.vendorExtensions.getOrDefault("x-terraform-path-fmt", readOp.path));
objectMap.put("readHasPathParams", readOp.pathParams != null && !readOp.pathParams.isEmpty());
}
if (updateOp != null) {
objectMap.put("updateMethod", updateOp.vendorExtensions.get("x-terraform-http-method"));
objectMap.put("updatePath", updateOp.vendorExtensions.getOrDefault("x-terraform-path-fmt", updateOp.path));
objectMap.put("updateHasPathParams", updateOp.pathParams != null && !updateOp.pathParams.isEmpty());
}
if (deleteOp != null) {
objectMap.put("deleteMethod", deleteOp.vendorExtensions.get("x-terraform-http-method"));
objectMap.put("deletePath", deleteOp.vendorExtensions.getOrDefault("x-terraform-path-fmt", deleteOp.path));
objectMap.put("deleteHasPathParams", deleteOp.pathParams != null && !deleteOp.pathParams.isEmpty());
}
// Determine resource name from tag
String tag = objectMap.getClassname();
// Strip common suffixes like "Api", "API" from the tag name
String cleanTag = tag.replaceAll("(?i)api$", "");
if (cleanTag.isEmpty()) {
cleanTag = tag;
}
String resourceName = underscore(cleanTag).toLowerCase(Locale.ROOT);
// Allow override via x-terraform-resource-name on any operation
for (CodegenOperation op : operations) {
Object nameOverride = op.vendorExtensions.get("x-terraform-resource-name");
if (nameOverride != null) {
resourceName = nameOverride.toString();
break;
}
}
objectMap.put("resourceName", resourceName);
objectMap.put("resourceClassName", camelize(resourceName));
// Detect ID field from read operation path params
String idField = "id";
if (readOp != null && readOp.pathParams != null && !readOp.pathParams.isEmpty()) {
idField = readOp.pathParams.get(readOp.pathParams.size() - 1).paramName;
}
objectMap.put("idField", idField);
// Build model info for the resource schema
// Use the response type from readOp (or createOp) as the resource model
String responseModel = null;
if (readOp != null && readOp.returnType != null) {
responseModel = readOp.returnType;
} else if (createOp != null && createOp.returnType != null) {
responseModel = createOp.returnType;
}
objectMap.put("responseModel", responseModel);
// Build request model from createOp body params
String requestModel = null;
if (createOp != null && createOp.bodyParam != null && createOp.bodyParam.dataType != null) {
requestModel = createOp.bodyParam.dataType;
}
objectMap.put("requestModel", requestModel);
// Collect model properties for schema generation and resolve ID field
String idModelGoName = camelize(idField);
String idModelGoType = "string";
if (responseModel != null) {
for (ModelMap modelMap : allModels) {
CodegenModel model = modelMap.getModel();
if (model.classname.equals(responseModel)) {
List<Map<String, Object>> tfAttributes = new ArrayList<>();
boolean hasListAttributes = false;
for (CodegenProperty prop : model.vars) {
Map<String, Object> attr = new HashMap<>();
attr.put("name", prop.baseName);
attr.put("terraformName", underscore(prop.baseName).toLowerCase(Locale.ROOT));
attr.put("goName", camelize(prop.baseName));
attr.put("goType", prop.dataType);
attr.put("terraformType", goTypeToTerraformType(prop.dataType));
attr.put("terraformAttrType", goTypeToTerraformAttrType(prop.dataType, prop));
attr.put("isRequired", prop.required);
attr.put("isComputed", prop.isReadOnly);
attr.put("isOptional", !prop.required && !prop.isReadOnly);
attr.put("description", prop.description != null ? prop.description : "");
attr.put("isSensitive", prop.isWriteOnly || getBooleanVendorExtension(prop, "x-terraform-sensitive"));
attr.put("isString", "string".equals(prop.dataType));
attr.put("isInt64", "int64".equals(prop.dataType) || "int32".equals(prop.dataType));
attr.put("isFloat64", "float64".equals(prop.dataType) || "float32".equals(prop.dataType));
attr.put("isBool", "bool".equals(prop.dataType));
attr.put("isList", prop.isArray);
attr.put("isObject", prop.isModel && !prop.isArray);
if (prop.isArray) {
hasListAttributes = true;
if (prop.items != null) {
attr.put("listElementType", goTypeToTerraformElementType(prop.items.dataType));
}
}
tfAttributes.add(attr);
}
objectMap.put("tfAttributes", tfAttributes);
objectMap.put("hasListAttributes", hasListAttributes);
// Resolve ID field: match path param name to a model property
boolean idResolved = false;
// Try exact match on baseName (case-insensitive)
for (CodegenProperty prop : model.vars) {
if (prop.baseName.equalsIgnoreCase(idField)) {
idModelGoName = camelize(prop.baseName);
idModelGoType = prop.dataType;
idResolved = true;
break;
}
}
// Try stripping resource name prefix (e.g., petId -> id)
if (!idResolved) {
String strippedId = idField.replaceFirst("(?i)^" + resourceName, "");
if (!strippedId.isEmpty()) {
for (CodegenProperty prop : model.vars) {
if (prop.baseName.equalsIgnoreCase(strippedId)) {
idModelGoName = camelize(prop.baseName);
idModelGoType = prop.dataType;
idResolved = true;
break;
}
}
}
}
// Fall back to "id" property
if (!idResolved) {
for (CodegenProperty prop : model.vars) {
if ("id".equalsIgnoreCase(prop.baseName)) {
idModelGoName = camelize(prop.baseName);
idModelGoType = prop.dataType;
break;
}
}
}
break;
}
}
}
objectMap.put("idFieldExported", idModelGoName);
// Determine the value accessor for the ID field based on its type
String idValueAccessor;
if ("int64".equals(idModelGoType) || "int32".equals(idModelGoType) || "int".equals(idModelGoType)) {
idValueAccessor = ".ValueInt64()";
} else if ("float64".equals(idModelGoType) || "float32".equals(idModelGoType)) {
idValueAccessor = ".ValueFloat64()";
} else {
idValueAccessor = ".ValueString()";
}
objectMap.put("idFieldValueAccessor", idValueAccessor);
// Terraform name for the ID field (for path.Root in ImportState)
objectMap.put("idFieldTerraformName", underscore(idModelGoName).toLowerCase(Locale.ROOT));
return objs;
}
@Override
public ModelsMap postProcessModels(ModelsMap objs) {
// Call parent to handle Go-specific post-processing
objs = super.postProcessModels(objs);
for (ModelMap m : objs.getModels()) {
CodegenModel model = m.getModel();
for (CodegenProperty prop : model.vars) {
// Ensure x-go-datatag is set for all model vars.
// The parent AbstractGoCodegen only sets x-go-datatag on
// inheritedProperties (oneOf/anyOf entries) when the model has
// composed schemas without allOf, leaving model.vars without
// json tags. We fix this by generating the tag here when missing.
if (!prop.vendorExtensions.containsKey("x-go-datatag")) {
String goDataTag = "json:\"" + prop.baseName;
if (!prop.required) {
goDataTag += ",omitempty";
}
goDataTag += "\"";
goDataTag = " `" + goDataTag + "`";
prop.vendorExtensions.put("x-go-datatag", goDataTag);
}
// Add Terraform-specific vendor extensions
if (prop.isReadOnly) {
prop.vendorExtensions.put("x-terraform-computed", true);
}
if (prop.required) {
prop.vendorExtensions.put("x-terraform-required", true);
}
if (!prop.required && !prop.isReadOnly) {
prop.vendorExtensions.put("x-terraform-optional", true);
}
if (prop.isWriteOnly) {
prop.vendorExtensions.put("x-terraform-sensitive", true);
}
// Map Go types to Terraform types
prop.vendorExtensions.put("x-terraform-type", goTypeToTerraformType(prop.dataType));
prop.vendorExtensions.put("x-terraform-attr-type", goTypeToTerraformAttrType(prop.dataType, prop));
}
}
return objs;
}
private String goTypeToTerraformType(String goType) {
if (goType == null) return "types.String";
switch (goType) {
case "string":
return "types.String";
case "int32":
case "int64":
case "int":
return "types.Int64";
case "float32":
case "float64":
return "types.Float64";
case "bool":
return "types.Bool";
default:
if (goType.startsWith("[]")) {
return "types.List";
}
return "types.String";
}
}
private String goTypeToTerraformAttrType(String goType, CodegenProperty prop) {
if (goType == null) return "schema.StringAttribute";
switch (goType) {
case "string":
return "schema.StringAttribute";
case "int32":
case "int64":
case "int":
return "schema.Int64Attribute";
case "float32":
case "float64":
return "schema.Float64Attribute";
case "bool":
return "schema.BoolAttribute";
default:
if (goType.startsWith("[]")) {
return "schema.ListAttribute";
}
// Complex objects are serialized as JSON strings
return "schema.StringAttribute";
}
}
private String goTypeToTerraformElementType(String goType) {
if (goType == null) return "types.StringType";
switch (goType) {
case "string":
return "types.StringType";
case "int32":
case "int64":
case "int":
return "types.Int64Type";
case "float32":
case "float64":
return "types.Float64Type";
case "bool":
return "types.BoolType";
default:
return "types.StringType";
}
}
private boolean getBooleanVendorExtension(CodegenOperation op, String key) {
return op.vendorExtensions.containsKey(key) && Boolean.TRUE.equals(op.vendorExtensions.get(key));
}
private boolean getBooleanVendorExtension(CodegenProperty prop, String key) {
return prop.vendorExtensions.containsKey(key) && Boolean.TRUE.equals(prop.vendorExtensions.get(key));
}
}

View File

@@ -149,6 +149,7 @@ org.openapitools.codegen.languages.StaticHtml2Generator
org.openapitools.codegen.languages.Swift5ClientCodegen
org.openapitools.codegen.languages.Swift6ClientCodegen
org.openapitools.codegen.languages.SwiftCombineClientCodegen
org.openapitools.codegen.languages.TerraformProviderCodegen
org.openapitools.codegen.languages.TypeScriptClientCodegen
org.openapitools.codegen.languages.TypeScriptAngularClientCodegen
org.openapitools.codegen.languages.TypeScriptAureliaClientCodegen

View File

@@ -0,0 +1,27 @@
default: testacc
# Run acceptance tests
.PHONY: testacc
testacc:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
# Build provider
.PHONY: build
build:
go build -o terraform-provider-{{providerName}}
# Install provider locally
.PHONY: install
install: build
mkdir -p ~/.terraform.d/plugins/{{providerAddress}}/{{providerVersion}}/$(shell go env GOOS)_$(shell go env GOARCH)
mv terraform-provider-{{providerName}} ~/.terraform.d/plugins/{{providerAddress}}/{{providerVersion}}/$(shell go env GOOS)_$(shell go env GOARCH)/
# Generate documentation
.PHONY: docs
docs:
go generate ./...
# Run linter
.PHONY: lint
lint:
golangci-lint run ./...

View File

@@ -0,0 +1,61 @@
# Terraform Provider {{providerName}}
This Terraform provider was generated using [OpenAPI Generator](https://openapi-generator.tech).
## Requirements
- [Terraform](https://www.terraform.io/downloads.html) >= 1.0
- [Go](https://golang.org/doc/install) >= 1.22
## Building The Provider
1. Clone the repository
2. Enter the repository directory
3. Build the provider using the Go `install` command:
```shell
go install
```
## Using the provider
```hcl
terraform {
required_providers {
{{providerName}} = {
source = "{{providerAddress}}"
}
}
}
provider "{{providerName}}" {
endpoint = "{{basePath}}"
}
```
## Developing the Provider
If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above).
To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.
For local development and testing, add a `dev_overrides` block to your `~/.terraformrc` so that Terraform uses the locally built binary instead of fetching from the registry:
```hcl
provider_installation {
dev_overrides {
"{{providerAddress}}" = "${GOPATH}/bin"
}
direct {}
}
```
With `dev_overrides` configured, you do not need to run `terraform init` for the provider.
To generate or update documentation, run `go generate`.
In order to run the full suite of Acceptance tests, run `make testacc`.
```shell
make testacc
```

View File

@@ -0,0 +1,77 @@
{{>partial_header}}
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
// Client is the API client used to interact with the API.
type Client struct {
BaseURL string
HTTPClient *http.Client
ApiKey string
Token string
Username string
Password string
}
// NewClient creates a new API client with the given base URL.
func NewClient(baseURL string) *Client {
return &Client{
BaseURL: baseURL,
HTTPClient: &http.Client{},
}
}
// DoRequest executes an HTTP request and returns the response body.
func (c *Client) DoRequest(ctx context.Context, method, path string, body interface{}) ([]byte, error) {
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("error marshaling request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequestWithContext(ctx, method, c.BaseURL+path, reqBody)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
// Authentication
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
} else if c.ApiKey != "" {
req.Header.Set("Authorization", c.ApiKey)
} else if c.Username != "" {
req.SetBasicAuth(c.Username, c.Password)
}
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(respBody))
}
return respBody, nil
}

View File

@@ -0,0 +1,108 @@
{{#operations}}
{{>partial_header}}
package provider
import (
"context"
"fmt"
{{#hasRead}}
"encoding/json"
{{/hasRead}}
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
{{#hasRead}}
"github.com/hashicorp/terraform-plugin-log/tflog"
{{/hasRead}}
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/internal/client"
)
var _ datasource.DataSource = &{{resourceClassName}}DataSource{}
func New{{resourceClassName}}DataSource() datasource.DataSource {
return &{{resourceClassName}}DataSource{}
}
type {{resourceClassName}}DataSource struct {
client *client.Client
}
func (d *{{resourceClassName}}DataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_{{resourceName}}"
}
func (d *{{resourceClassName}}DataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Fetches a {{resourceName}} data source.",
Attributes: map[string]schema.Attribute{
{{#tfAttributes}}
"{{terraformName}}": schema.{{#isString}}String{{/isString}}{{#isInt64}}Int64{{/isInt64}}{{#isFloat64}}Float64{{/isFloat64}}{{#isBool}}Bool{{/isBool}}{{^isString}}{{^isInt64}}{{^isFloat64}}{{^isBool}}String{{/isBool}}{{/isFloat64}}{{/isInt64}}{{/isString}}Attribute{
{{#isRequired}}
Required: true,
{{/isRequired}}
{{^isRequired}}
Computed: true,
{{/isRequired}}
Description: "{{description}}",
},
{{/tfAttributes}}
},
}
}
func (d *{{resourceClassName}}DataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
c, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T.", req.ProviderData),
)
return
}
d.client = c
}
{{#hasRead}}
func (d *{{resourceClassName}}DataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var config {{resourceClassName}}Model
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
{{#readHasPathParams}}
respBody, err := d.client.DoRequest(ctx, "{{readMethod}}", fmt.Sprintf("{{readPath}}", config.{{idFieldExported}}{{idFieldValueAccessor}}), nil)
{{/readHasPathParams}}
{{^readHasPathParams}}
respBody, err := d.client.DoRequest(ctx, "{{readMethod}}", "{{readPath}}", nil)
{{/readHasPathParams}}
if err != nil {
resp.Diagnostics.AddError("Error reading {{resourceName}}", err.Error())
return
}
var result client.{{responseModel}}
if err := json.Unmarshal(respBody, &result); err != nil {
resp.Diagnostics.AddError("Error parsing response", err.Error())
return
}
config.FromClientModel(&result)
tflog.Trace(ctx, "read {{resourceName}} data source")
resp.Diagnostics.Append(resp.State.Set(ctx, &config)...)
}
{{/hasRead}}
{{^hasRead}}
func (d *{{resourceClassName}}DataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
resp.Diagnostics.AddError("Not Supported", "Read is not supported for {{resourceName}}")
}
{{/hasRead}}
{{/operations}}

View File

@@ -0,0 +1,13 @@
*.dll
*.exe
*.exe~
*.dylib
*.so
*.test
*.out
*.tfstate
*.tfstate.*
.terraform/
*.tfvars
*.tfvars.json
terraform-provider-{{providerName}}

View File

@@ -0,0 +1,11 @@
module {{gitHost}}/{{gitUserId}}/{{gitRepoId}}
go 1.24.0
toolchain go1.24.4
require (
github.com/hashicorp/terraform-plugin-framework v1.17.0
github.com/hashicorp/terraform-plugin-log v0.10.0
github.com/hashicorp/terraform-plugin-testing v1.14.0
)

View File

@@ -0,0 +1,34 @@
{{>partial_header}}
package main
import (
"context"
"flag"
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/internal/provider"
)
var (
version string = "{{providerVersion}}"
)
func main() {
var debug bool
flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
opts := providerserver.ServeOpts{
Address: "{{providerAddress}}",
Debug: debug,
}
err := providerserver.Serve(context.Background(), provider.New(version), opts)
if err != nil {
log.Fatal(err.Error())
}
}

View File

@@ -0,0 +1,13 @@
{{>partial_header}}
package client
{{#models}}
{{#model}}
// {{classname}} - {{{description}}}{{^description}}{{classname}} struct{{/description}}
type {{classname}} struct {
{{#vars}}
{{name}} {{#isArray}}[]{{#items}}{{dataType}}{{/items}}{{/isArray}}{{^isArray}}{{#isMap}}map[string]{{#items}}{{dataType}}{{/items}}{{/isMap}}{{^isMap}}{{dataType}}{{/isMap}}{{/isArray}}{{{vendorExtensions.x-go-datatag}}}
{{/vars}}
}
{{/model}}
{{/models}}

View File

@@ -0,0 +1 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.

View File

@@ -0,0 +1,122 @@
{{>partial_header}}
package provider
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/internal/client"
)
var _ provider.Provider = &{{providerName}}Provider{}
type {{providerName}}Provider struct {
version string
}
type {{providerName}}ProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`
ApiKey types.String `tfsdk:"api_key"`
Token types.String `tfsdk:"token"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &{{providerName}}Provider{
version: version,
}
}
}
func (p *{{providerName}}Provider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "{{providerName}}"
resp.Version = p.version
}
func (p *{{providerName}}Provider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"endpoint": schema.StringAttribute{
Optional: true,
Description: "The API endpoint URL.",
},
"api_key": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The API key for authentication.",
},
"token": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The bearer token for authentication.",
},
"username": schema.StringAttribute{
Optional: true,
Description: "The username for basic authentication.",
},
"password": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The password for basic authentication.",
},
},
}
}
func (p *{{providerName}}Provider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var config {{providerName}}ProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
if config.Endpoint.IsUnknown() {
resp.Diagnostics.AddWarning(
"Unknown Endpoint Value",
"The provider endpoint value is not yet known. Defaulting to the spec-defined base path.",
)
}
endpoint := "{{{basePath}}}"
if !config.Endpoint.IsNull() && !config.Endpoint.IsUnknown() {
endpoint = config.Endpoint.ValueString()
}
c := client.NewClient(endpoint)
if !config.ApiKey.IsNull() {
c.ApiKey = config.ApiKey.ValueString()
}
if !config.Token.IsNull() {
c.Token = config.Token.ValueString()
}
if !config.Username.IsNull() {
c.Username = config.Username.ValueString()
}
if !config.Password.IsNull() {
c.Password = config.Password.ValueString()
}
resp.DataSourceData = c
resp.ResourceData = c
}
func (p *{{providerName}}Provider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
{{#apiInfo}}{{#apis}}{{#operations}} New{{resourceClassName}}Resource,
{{/operations}}{{/apis}}{{/apiInfo}} }
}
func (p *{{providerName}}Provider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
{{#apiInfo}}{{#apis}}{{#operations}} New{{resourceClassName}}DataSource,
{{/operations}}{{/apis}}{{/apiInfo}} }
}

View File

@@ -0,0 +1,13 @@
terraform {
required_providers {
{{providerName}} = {
source = "{{providerAddress}}"
}
}
}
provider "{{providerName}}" {
endpoint = "{{{basePath}}}"
# api_key = "your-api-key"
# token = "your-bearer-token"
}

View File

@@ -0,0 +1,247 @@
{{#operations}}
{{>partial_header}}
package provider
import (
"context"
"fmt"
{{#hasCreate}}
"encoding/json"
{{/hasCreate}}
{{^hasCreate}}{{#hasRead}}
"encoding/json"
{{/hasRead}}{{/hasCreate}}
{{^hasCreate}}{{^hasRead}}{{#hasUpdate}}
"encoding/json"
{{/hasUpdate}}{{/hasRead}}{{/hasCreate}}
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
{{#hasListAttributes}}
"github.com/hashicorp/terraform-plugin-framework/types"
{{/hasListAttributes}}
{{#hasCreate}}
"github.com/hashicorp/terraform-plugin-log/tflog"
{{/hasCreate}}
{{^hasCreate}}{{#hasUpdate}}
"github.com/hashicorp/terraform-plugin-log/tflog"
{{/hasUpdate}}{{/hasCreate}}
{{^hasCreate}}{{^hasUpdate}}{{#hasDelete}}
"github.com/hashicorp/terraform-plugin-log/tflog"
{{/hasDelete}}{{/hasUpdate}}{{/hasCreate}}
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/internal/client"
)
var _ resource.Resource = &{{resourceClassName}}Resource{}
var _ resource.ResourceWithImportState = &{{resourceClassName}}Resource{}
func New{{resourceClassName}}Resource() resource.Resource {
return &{{resourceClassName}}Resource{}
}
type {{resourceClassName}}Resource struct {
client *client.Client
}
func (r *{{resourceClassName}}Resource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_{{resourceName}}"
}
func (r *{{resourceClassName}}Resource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Manages a {{resourceName}} resource.",
Attributes: map[string]schema.Attribute{
{{#tfAttributes}}
"{{terraformName}}": {{terraformAttrType}}{
{{#isRequired}}
Required: true,
{{/isRequired}}
{{#isComputed}}
Computed: true,
{{/isComputed}}
{{#isOptional}}
Optional: true,
{{/isOptional}}
{{#isSensitive}}
Sensitive: true,
{{/isSensitive}}
{{#isList}}
ElementType: {{listElementType}},
{{/isList}}
Description: "{{description}}",
},
{{/tfAttributes}}
},
}
}
func (r *{{resourceClassName}}Resource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
c, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T.", req.ProviderData),
)
return
}
r.client = c
}
{{#hasCreate}}
func (r *{{resourceClassName}}Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan {{resourceClassName}}Model
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
reqBody := plan.ToClientModel()
respBody, err := r.client.DoRequest(ctx, "{{createMethod}}", "{{createPath}}", reqBody)
if err != nil {
resp.Diagnostics.AddError("Error creating {{resourceName}}", err.Error())
return
}
var result client.{{responseModel}}
if err := json.Unmarshal(respBody, &result); err != nil {
resp.Diagnostics.AddError("Error parsing response", err.Error())
return
}
plan.FromClientModel(&result)
tflog.Trace(ctx, "created {{resourceName}} resource")
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}
{{/hasCreate}}
{{^hasCreate}}
func (r *{{resourceClassName}}Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
resp.Diagnostics.AddError("Not Supported", "Create is not supported for {{resourceName}}")
}
{{/hasCreate}}
{{#hasRead}}
func (r *{{resourceClassName}}Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state {{resourceClassName}}Model
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
{{#readHasPathParams}}
respBody, err := r.client.DoRequest(ctx, "{{readMethod}}", fmt.Sprintf("{{readPath}}", state.{{idFieldExported}}{{idFieldValueAccessor}}), nil)
{{/readHasPathParams}}
{{^readHasPathParams}}
respBody, err := r.client.DoRequest(ctx, "{{readMethod}}", "{{readPath}}", nil)
{{/readHasPathParams}}
if err != nil {
resp.Diagnostics.AddError("Error reading {{resourceName}}", err.Error())
return
}
var result client.{{responseModel}}
if err := json.Unmarshal(respBody, &result); err != nil {
resp.Diagnostics.AddError("Error parsing response", err.Error())
return
}
state.FromClientModel(&result)
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
{{/hasRead}}
{{^hasRead}}
func (r *{{resourceClassName}}Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// No read endpoint available; keep existing state as-is.
}
{{/hasRead}}
{{#hasUpdate}}
func (r *{{resourceClassName}}Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var plan {{resourceClassName}}Model
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
reqBody := plan.ToClientModel()
{{#updateHasPathParams}}
respBody, err := r.client.DoRequest(ctx, "{{updateMethod}}", fmt.Sprintf("{{updatePath}}", plan.{{idFieldExported}}{{idFieldValueAccessor}}), reqBody)
{{/updateHasPathParams}}
{{^updateHasPathParams}}
respBody, err := r.client.DoRequest(ctx, "{{updateMethod}}", "{{updatePath}}", reqBody)
{{/updateHasPathParams}}
if err != nil {
resp.Diagnostics.AddError("Error updating {{resourceName}}", err.Error())
return
}
var result client.{{responseModel}}
if err := json.Unmarshal(respBody, &result); err != nil {
resp.Diagnostics.AddError("Error parsing response", err.Error())
return
}
plan.FromClientModel(&result)
tflog.Trace(ctx, "updated {{resourceName}} resource")
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}
{{/hasUpdate}}
{{^hasUpdate}}
func (r *{{resourceClassName}}Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
// No update endpoint available; persist the planned values into state.
var plan {{resourceClassName}}Model
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}
{{/hasUpdate}}
{{#hasDelete}}
func (r *{{resourceClassName}}Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state {{resourceClassName}}Model
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
{{#deleteHasPathParams}}
_, err := r.client.DoRequest(ctx, "{{deleteMethod}}", fmt.Sprintf("{{deletePath}}", state.{{idFieldExported}}{{idFieldValueAccessor}}), nil)
{{/deleteHasPathParams}}
{{^deleteHasPathParams}}
_, err := r.client.DoRequest(ctx, "{{deleteMethod}}", "{{deletePath}}", nil)
{{/deleteHasPathParams}}
if err != nil {
resp.Diagnostics.AddError("Error deleting {{resourceName}}", err.Error())
return
}
tflog.Trace(ctx, "deleted {{resourceName}} resource")
}
{{/hasDelete}}
{{^hasDelete}}
func (r *{{resourceClassName}}Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
// No delete endpoint available; remove the resource from state.
}
{{/hasDelete}}
func (r *{{resourceClassName}}Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("{{idFieldTerraformName}}"), req, resp)
}
{{/operations}}

View File

@@ -0,0 +1,67 @@
{{#operations}}
{{>partial_header}}
package provider
{{#responseModel}}
import (
"github.com/hashicorp/terraform-plugin-framework/types"
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/internal/client"
)
{{/responseModel}}
// {{resourceClassName}}Model is the Terraform model for {{resourceName}}.
type {{resourceClassName}}Model struct {
{{#tfAttributes}}
{{goName}} {{terraformType}} `tfsdk:"{{terraformName}}"`
{{/tfAttributes}}
}
{{#responseModel}}
// ToClientModel converts a Terraform model to a client model.
func (m *{{resourceClassName}}Model) ToClientModel() *client.{{responseModel}} {
out := &client.{{responseModel}}{}
{{#tfAttributes}}
{{#isString}}
if !m.{{goName}}.IsNull() && !m.{{goName}}.IsUnknown() {
out.{{goName}} = m.{{goName}}.ValueString()
}
{{/isString}}
{{#isInt64}}
if !m.{{goName}}.IsNull() && !m.{{goName}}.IsUnknown() {
out.{{goName}} = {{goType}}(m.{{goName}}.ValueInt64())
}
{{/isInt64}}
{{#isFloat64}}
if !m.{{goName}}.IsNull() && !m.{{goName}}.IsUnknown() {
out.{{goName}} = {{goType}}(m.{{goName}}.ValueFloat64())
}
{{/isFloat64}}
{{#isBool}}
if !m.{{goName}}.IsNull() && !m.{{goName}}.IsUnknown() {
out.{{goName}} = m.{{goName}}.ValueBool()
}
{{/isBool}}
{{/tfAttributes}}
return out
}
// FromClientModel updates the Terraform model from a client model.
func (m *{{resourceClassName}}Model) FromClientModel(c *client.{{responseModel}}) {
{{#tfAttributes}}
{{#isString}}
m.{{goName}} = types.StringValue(c.{{goName}})
{{/isString}}
{{#isInt64}}
m.{{goName}} = types.Int64Value(int64(c.{{goName}}))
{{/isInt64}}
{{#isFloat64}}
m.{{goName}} = types.Float64Value(float64(c.{{goName}}))
{{/isFloat64}}
{{#isBool}}
m.{{goName}} = types.BoolValue(c.{{goName}})
{{/isBool}}
{{/tfAttributes}}
}
{{/responseModel}}
{{/operations}}

View File

@@ -0,0 +1,180 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.terraform.provider;
import org.openapitools.codegen.*;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.languages.TerraformProviderCodegen;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TerraformProviderCodegenTest {
@Test
public void testInitialConfigValues() throws Exception {
final TerraformProviderCodegen codegen = new TerraformProviderCodegen();
codegen.processOpts();
Assert.assertEquals(codegen.getName(), "terraform-provider");
Assert.assertEquals(codegen.getTag(), CodegenType.CLIENT);
Assert.assertNotNull(codegen.getHelp());
Assert.assertTrue(codegen.getHelp().contains("Terraform"));
}
@Test
public void testProviderNameOption() throws Exception {
final TerraformProviderCodegen codegen = new TerraformProviderCodegen();
codegen.additionalProperties().put(TerraformProviderCodegen.PROVIDER_NAME, "myapi");
codegen.processOpts();
Assert.assertEquals(codegen.additionalProperties().get(TerraformProviderCodegen.PROVIDER_NAME), "myapi");
}
@Test
public void testGeneratePetstore() throws Exception {
File output = Files.createTempDirectory("terraform-provider-test").toFile();
output.deleteOnExit();
Map<String, Object> properties = new HashMap<>();
properties.put(TerraformProviderCodegen.PROVIDER_NAME, "petstore");
properties.put(TerraformProviderCodegen.PROVIDER_ADDRESS, "registry.terraform.io/example/petstore");
properties.put("gitHost", "github.com");
properties.put("gitUserId", "example");
properties.put("gitRepoId", "terraform-provider-petstore");
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("terraform-provider")
.setAdditionalProperties(properties)
.setInputSpec("src/test/resources/3_0/petstore.yaml")
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
files.forEach(File::deleteOnExit);
// Verify key files exist
TestUtils.assertFileExists(Paths.get(output + "/main.go"));
TestUtils.assertFileExists(Paths.get(output + "/go.mod"));
TestUtils.assertFileExists(Paths.get(output + "/GNUmakefile"));
TestUtils.assertFileExists(Paths.get(output + "/README.md"));
TestUtils.assertFileExists(Paths.get(output + "/.gitignore"));
TestUtils.assertFileExists(Paths.get(output + "/internal/provider/provider.go"));
TestUtils.assertFileExists(Paths.get(output + "/internal/client/client.go"));
TestUtils.assertFileExists(Paths.get(output + "/examples/provider/provider.tf"));
}
@Test
public void testMainGoContent() throws Exception {
File output = Files.createTempDirectory("terraform-provider-test").toFile();
output.deleteOnExit();
Map<String, Object> properties = new HashMap<>();
properties.put(TerraformProviderCodegen.PROVIDER_NAME, "petstore");
properties.put(TerraformProviderCodegen.PROVIDER_ADDRESS, "registry.terraform.io/example/petstore");
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("terraform-provider")
.setAdditionalProperties(properties)
.setGitHost("github.com")
.setGitUserId("example")
.setGitRepoId("terraform-provider-petstore")
.setInputSpec("src/test/resources/3_0/petstore.yaml")
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
files.forEach(File::deleteOnExit);
// Verify main.go content
TestUtils.assertFileContains(Paths.get(output + "/main.go"), "providerserver.Serve");
TestUtils.assertFileContains(Paths.get(output + "/main.go"), "registry.terraform.io/example/petstore");
// Verify provider.go content
TestUtils.assertFileContains(Paths.get(output + "/internal/provider/provider.go"), "petstoreProvider");
TestUtils.assertFileContains(Paths.get(output + "/internal/provider/provider.go"), "provider.Provider");
// Verify client.go content
TestUtils.assertFileContains(Paths.get(output + "/internal/client/client.go"), "type Client struct");
TestUtils.assertFileContains(Paths.get(output + "/internal/client/client.go"), "func NewClient");
// Verify go.mod content
TestUtils.assertFileContains(Paths.get(output + "/go.mod"), "github.com/example/terraform-provider-petstore");
TestUtils.assertFileContains(Paths.get(output + "/go.mod"), "terraform-plugin-framework");
}
@Test
public void testTypeMapping() throws Exception {
final TerraformProviderCodegen codegen = new TerraformProviderCodegen();
codegen.processOpts();
// Terraform provider should map DateTime to string (not time.Time)
Assert.assertEquals(codegen.typeMapping().get("DateTime"), "string");
Assert.assertEquals(codegen.typeMapping().get("File"), "string");
Assert.assertEquals(codegen.typeMapping().get("binary"), "string");
// Standard Go type mappings should still work
Assert.assertEquals(codegen.typeMapping().get("integer"), "int32");
Assert.assertEquals(codegen.typeMapping().get("long"), "int64");
Assert.assertEquals(codegen.typeMapping().get("boolean"), "bool");
Assert.assertEquals(codegen.typeMapping().get("string"), "string");
}
@Test
public void testFilenames() throws Exception {
final TerraformProviderCodegen codegen = new TerraformProviderCodegen();
Assert.assertEquals(codegen.toApiFilename("Pet"), "pet");
Assert.assertEquals(codegen.toApiFilename("UserProfile"), "user_profile");
Assert.assertEquals(codegen.toModelFilename("Pet"), "model_pet");
Assert.assertEquals(codegen.toModelFilename("ApiResponse"), "model_api_response");
}
@Test
public void testProviderExampleContent() throws Exception {
File output = Files.createTempDirectory("terraform-provider-test").toFile();
output.deleteOnExit();
Map<String, Object> properties = new HashMap<>();
properties.put(TerraformProviderCodegen.PROVIDER_NAME, "petstore");
properties.put(TerraformProviderCodegen.PROVIDER_ADDRESS, "registry.terraform.io/example/petstore");
properties.put("gitHost", "github.com");
properties.put("gitUserId", "example");
properties.put("gitRepoId", "terraform-provider-petstore");
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("terraform-provider")
.setAdditionalProperties(properties)
.setInputSpec("src/test/resources/3_0/petstore.yaml")
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
files.forEach(File::deleteOnExit);
// Verify provider example
TestUtils.assertFileContains(Paths.get(output + "/examples/provider/provider.tf"), "petstore");
TestUtils.assertFileContains(Paths.get(output + "/examples/provider/provider.tf"), "registry.terraform.io/example/petstore");
}
}

View File

@@ -0,0 +1,13 @@
*.dll
*.exe
*.exe~
*.dylib
*.so
*.test
*.out
*.tfstate
*.tfstate.*
.terraform/
*.tfvars
*.tfvars.json
terraform-provider-allof

View File

@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@@ -0,0 +1,11 @@
.gitignore
GNUmakefile
README.md
examples/provider/provider.tf
go.mod
internal/client/client.go
internal/client/model_additional_data.go
internal/client/model_base/item.go
internal/client/model_final_item.go
internal/provider/provider.go
main.go

View File

@@ -0,0 +1 @@
7.20.0-SNAPSHOT

View File

@@ -0,0 +1,27 @@
default: testacc
# Run acceptance tests
.PHONY: testacc
testacc:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
# Build provider
.PHONY: build
build:
go build -o terraform-provider-allof
# Install provider locally
.PHONY: install
install: build
mkdir -p ~/.terraform.d/plugins/registry.terraform.io/example/allof/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)
mv terraform-provider-allof ~/.terraform.d/plugins/registry.terraform.io/example/allof/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)/
# Generate documentation
.PHONY: docs
docs:
go generate ./...
# Run linter
.PHONY: lint
lint:
golangci-lint run ./...

View File

@@ -0,0 +1,61 @@
# Terraform Provider allof
This Terraform provider was generated using [OpenAPI Generator](https://openapi-generator.tech).
## Requirements
- [Terraform](https://www.terraform.io/downloads.html) >= 1.0
- [Go](https://golang.org/doc/install) >= 1.22
## Building The Provider
1. Clone the repository
2. Enter the repository directory
3. Build the provider using the Go `install` command:
```shell
go install
```
## Using the provider
```hcl
terraform {
required_providers {
allof = {
source = "registry.terraform.io/example/allof"
}
}
}
provider "allof" {
endpoint = "http://localhost"
}
```
## Developing the Provider
If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above).
To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.
For local development and testing, add a `dev_overrides` block to your `~/.terraformrc` so that Terraform uses the locally built binary instead of fetching from the registry:
```hcl
provider_installation {
dev_overrides {
"registry.terraform.io/example/allof" = "${GOPATH}/bin"
}
direct {}
}
```
With `dev_overrides` configured, you do not need to run `terraform init` for the provider.
To generate or update documentation, run `go generate`.
In order to run the full suite of Acceptance tests, run `make testacc`.
```shell
make testacc
```

View File

@@ -0,0 +1,13 @@
terraform {
required_providers {
allof = {
source = "registry.terraform.io/example/allof"
}
}
}
provider "allof" {
endpoint = "http://localhost"
# api_key = "your-api-key"
# token = "your-bearer-token"
}

View File

@@ -0,0 +1,11 @@
module github.com/example/terraform-provider-allof
go 1.24.0
toolchain go1.24.4
require (
github.com/hashicorp/terraform-plugin-framework v1.17.0
github.com/hashicorp/terraform-plugin-log v0.10.0
github.com/hashicorp/terraform-plugin-testing v1.14.0
)

View File

@@ -0,0 +1,99 @@
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-framework v1.17.0 h1:JdX50CFrYcYFY31gkmitAEAzLKoBgsK+iaJjDC8OexY=
github.com/hashicorp/terraform-plugin-framework v1.17.0/go.mod h1:4OUXKdHNosX+ys6rLgVlgklfxN3WHR5VHSOABeS/BM0=
github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
github.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,78 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
// Client is the API client used to interact with the API.
type Client struct {
BaseURL string
HTTPClient *http.Client
ApiKey string
Token string
Username string
Password string
}
// NewClient creates a new API client with the given base URL.
func NewClient(baseURL string) *Client {
return &Client{
BaseURL: baseURL,
HTTPClient: &http.Client{},
}
}
// DoRequest executes an HTTP request and returns the response body.
func (c *Client) DoRequest(ctx context.Context, method, path string, body interface{}) ([]byte, error) {
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("error marshaling request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequestWithContext(ctx, method, c.BaseURL+path, reqBody)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
// Authentication
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
} else if c.ApiKey != "" {
req.Header.Set("Authorization", c.ApiKey)
} else if c.Username != "" {
req.SetBasicAuth(c.Username, c.Password)
}
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(respBody))
}
return respBody, nil
}

View File

@@ -0,0 +1,11 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// AdditionalData - AdditionalData struct
type AdditionalData struct {
Prop1 string `json:"prop1"`
Quantity int32 `json:"quantity"`
UnitPrice float64 `json:"unitPrice"`
TotalPrice float64 `json:"totalPrice"`
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// BaseItem - BaseItem struct
type BaseItem struct {
Title string `json:"title"`
Type string `json:"type"`
}

View File

@@ -0,0 +1,11 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// FinalItem - FinalItem struct
type FinalItem struct {
Prop1 string `json:"prop1"`
Quantity int32 `json:"quantity"`
UnitPrice float64 `json:"unitPrice"`
TotalPrice float64 `json:"totalPrice"`
}

View File

@@ -0,0 +1,121 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package provider
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/example/terraform-provider-allof/internal/client"
)
var _ provider.Provider = &allofProvider{}
type allofProvider struct {
version string
}
type allofProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`
ApiKey types.String `tfsdk:"api_key"`
Token types.String `tfsdk:"token"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &allofProvider{
version: version,
}
}
}
func (p *allofProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "allof"
resp.Version = p.version
}
func (p *allofProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"endpoint": schema.StringAttribute{
Optional: true,
Description: "The API endpoint URL.",
},
"api_key": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The API key for authentication.",
},
"token": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The bearer token for authentication.",
},
"username": schema.StringAttribute{
Optional: true,
Description: "The username for basic authentication.",
},
"password": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The password for basic authentication.",
},
},
}
}
func (p *allofProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var config allofProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
if config.Endpoint.IsUnknown() {
resp.Diagnostics.AddWarning(
"Unknown Endpoint Value",
"The provider endpoint value is not yet known. Defaulting to the spec-defined base path.",
)
}
endpoint := "http://localhost"
if !config.Endpoint.IsNull() && !config.Endpoint.IsUnknown() {
endpoint = config.Endpoint.ValueString()
}
c := client.NewClient(endpoint)
if !config.ApiKey.IsNull() {
c.ApiKey = config.ApiKey.ValueString()
}
if !config.Token.IsNull() {
c.Token = config.Token.ValueString()
}
if !config.Username.IsNull() {
c.Username = config.Username.ValueString()
}
if !config.Password.IsNull() {
c.Password = config.Password.ValueString()
}
resp.DataSourceData = c
resp.ResourceData = c
}
func (p *allofProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
}
}
func (p *allofProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
}
}

View File

@@ -0,0 +1,35 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package main
import (
"context"
"flag"
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/example/terraform-provider-allof/internal/provider"
)
var (
version string = "0.1.0"
)
func main() {
var debug bool
flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
opts := providerserver.ServeOpts{
Address: "registry.terraform.io/example/allof",
Debug: debug,
}
err := providerserver.Serve(context.Background(), provider.New(version), opts)
if err != nil {
log.Fatal(err.Error())
}
}

View File

@@ -0,0 +1,13 @@
*.dll
*.exe
*.exe~
*.dylib
*.so
*.test
*.out
*.tfstate
*.tfstate.*
.terraform/
*.tfvars
*.tfvars.json
terraform-provider-oneof

View File

@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@@ -0,0 +1,12 @@
.gitignore
GNUmakefile
README.md
examples/provider/provider.tf
go.mod
internal/client/client.go
internal/client/model_nested_object1.go
internal/client/model_nested_object2.go
internal/client/model_object.go
internal/client/model_object2.go
internal/provider/provider.go
main.go

View File

@@ -0,0 +1 @@
7.20.0-SNAPSHOT

View File

@@ -0,0 +1,27 @@
default: testacc
# Run acceptance tests
.PHONY: testacc
testacc:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
# Build provider
.PHONY: build
build:
go build -o terraform-provider-oneof
# Install provider locally
.PHONY: install
install: build
mkdir -p ~/.terraform.d/plugins/registry.terraform.io/example/oneof-anyof/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)
mv terraform-provider-oneof ~/.terraform.d/plugins/registry.terraform.io/example/oneof-anyof/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)/
# Generate documentation
.PHONY: docs
docs:
go generate ./...
# Run linter
.PHONY: lint
lint:
golangci-lint run ./...

View File

@@ -0,0 +1,61 @@
# Terraform Provider oneof
This Terraform provider was generated using [OpenAPI Generator](https://openapi-generator.tech).
## Requirements
- [Terraform](https://www.terraform.io/downloads.html) >= 1.0
- [Go](https://golang.org/doc/install) >= 1.22
## Building The Provider
1. Clone the repository
2. Enter the repository directory
3. Build the provider using the Go `install` command:
```shell
go install
```
## Using the provider
```hcl
terraform {
required_providers {
oneof = {
source = "registry.terraform.io/example/oneof-anyof"
}
}
}
provider "oneof" {
endpoint = "http://localhost"
}
```
## Developing the Provider
If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above).
To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.
For local development and testing, add a `dev_overrides` block to your `~/.terraformrc` so that Terraform uses the locally built binary instead of fetching from the registry:
```hcl
provider_installation {
dev_overrides {
"registry.terraform.io/example/oneof-anyof" = "${GOPATH}/bin"
}
direct {}
}
```
With `dev_overrides` configured, you do not need to run `terraform init` for the provider.
To generate or update documentation, run `go generate`.
In order to run the full suite of Acceptance tests, run `make testacc`.
```shell
make testacc
```

View File

@@ -0,0 +1,13 @@
terraform {
required_providers {
oneof = {
source = "registry.terraform.io/example/oneof-anyof"
}
}
}
provider "oneof" {
endpoint = "http://localhost"
# api_key = "your-api-key"
# token = "your-bearer-token"
}

View File

@@ -0,0 +1,11 @@
module github.com/example/terraform-provider-oneof-anyof
go 1.24.0
toolchain go1.24.4
require (
github.com/hashicorp/terraform-plugin-framework v1.17.0
github.com/hashicorp/terraform-plugin-log v0.10.0
github.com/hashicorp/terraform-plugin-testing v1.14.0
)

View File

@@ -0,0 +1,99 @@
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-framework v1.17.0 h1:JdX50CFrYcYFY31gkmitAEAzLKoBgsK+iaJjDC8OexY=
github.com/hashicorp/terraform-plugin-framework v1.17.0/go.mod h1:4OUXKdHNosX+ys6rLgVlgklfxN3WHR5VHSOABeS/BM0=
github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
github.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,78 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
// Client is the API client used to interact with the API.
type Client struct {
BaseURL string
HTTPClient *http.Client
ApiKey string
Token string
Username string
Password string
}
// NewClient creates a new API client with the given base URL.
func NewClient(baseURL string) *Client {
return &Client{
BaseURL: baseURL,
HTTPClient: &http.Client{},
}
}
// DoRequest executes an HTTP request and returns the response body.
func (c *Client) DoRequest(ctx context.Context, method, path string, body interface{}) ([]byte, error) {
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("error marshaling request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequestWithContext(ctx, method, c.BaseURL+path, reqBody)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
// Authentication
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
} else if c.ApiKey != "" {
req.Header.Set("Authorization", c.ApiKey)
} else if c.Username != "" {
req.SetBasicAuth(c.Username, c.Password)
}
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(respBody))
}
return respBody, nil
}

View File

@@ -0,0 +1,8 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// NestedObject1 - NestedObject1 struct
type NestedObject1 struct {
Field1 string `json:"field1"`
}

View File

@@ -0,0 +1,8 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// NestedObject2 - NestedObject2 struct
type NestedObject2 struct {
Field2 string `json:"field2"`
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// Object - Object struct
type Object struct {
Field1 string `json:"field1"`
Field2 string `json:"field2"`
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// Object2 - Object2 struct
type Object2 struct {
Field1 string `json:"field1"`
Field2 string `json:"field2"`
}

View File

@@ -0,0 +1,121 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package provider
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/example/terraform-provider-oneof-anyof/internal/client"
)
var _ provider.Provider = &oneofProvider{}
type oneofProvider struct {
version string
}
type oneofProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`
ApiKey types.String `tfsdk:"api_key"`
Token types.String `tfsdk:"token"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &oneofProvider{
version: version,
}
}
}
func (p *oneofProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "oneof"
resp.Version = p.version
}
func (p *oneofProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"endpoint": schema.StringAttribute{
Optional: true,
Description: "The API endpoint URL.",
},
"api_key": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The API key for authentication.",
},
"token": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The bearer token for authentication.",
},
"username": schema.StringAttribute{
Optional: true,
Description: "The username for basic authentication.",
},
"password": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The password for basic authentication.",
},
},
}
}
func (p *oneofProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var config oneofProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
if config.Endpoint.IsUnknown() {
resp.Diagnostics.AddWarning(
"Unknown Endpoint Value",
"The provider endpoint value is not yet known. Defaulting to the spec-defined base path.",
)
}
endpoint := "http://localhost"
if !config.Endpoint.IsNull() && !config.Endpoint.IsUnknown() {
endpoint = config.Endpoint.ValueString()
}
c := client.NewClient(endpoint)
if !config.ApiKey.IsNull() {
c.ApiKey = config.ApiKey.ValueString()
}
if !config.Token.IsNull() {
c.Token = config.Token.ValueString()
}
if !config.Username.IsNull() {
c.Username = config.Username.ValueString()
}
if !config.Password.IsNull() {
c.Password = config.Password.ValueString()
}
resp.DataSourceData = c
resp.ResourceData = c
}
func (p *oneofProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
}
}
func (p *oneofProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
}
}

View File

@@ -0,0 +1,35 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package main
import (
"context"
"flag"
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/example/terraform-provider-oneof-anyof/internal/provider"
)
var (
version string = "0.1.0"
)
func main() {
var debug bool
flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
opts := providerserver.ServeOpts{
Address: "registry.terraform.io/example/oneof-anyof",
Debug: debug,
}
err := providerserver.Serve(context.Background(), provider.New(version), opts)
if err != nil {
log.Fatal(err.Error())
}
}

View File

@@ -0,0 +1,13 @@
*.dll
*.exe
*.exe~
*.dylib
*.so
*.test
*.out
*.tfstate
*.tfstate.*
.terraform/
*.tfvars
*.tfvars.json
terraform-provider-oneof

View File

@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@@ -0,0 +1,11 @@
.gitignore
GNUmakefile
README.md
examples/provider/provider.tf
go.mod
internal/client/client.go
internal/client/model_nested_object1.go
internal/client/model_nested_object2.go
internal/client/model_object.go
internal/provider/provider.go
main.go

View File

@@ -0,0 +1 @@
7.20.0-SNAPSHOT

View File

@@ -0,0 +1,27 @@
default: testacc
# Run acceptance tests
.PHONY: testacc
testacc:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
# Build provider
.PHONY: build
build:
go build -o terraform-provider-oneof
# Install provider locally
.PHONY: install
install: build
mkdir -p ~/.terraform.d/plugins/registry.terraform.io/example/oneof-disc/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)
mv terraform-provider-oneof ~/.terraform.d/plugins/registry.terraform.io/example/oneof-disc/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)/
# Generate documentation
.PHONY: docs
docs:
go generate ./...
# Run linter
.PHONY: lint
lint:
golangci-lint run ./...

View File

@@ -0,0 +1,61 @@
# Terraform Provider oneof
This Terraform provider was generated using [OpenAPI Generator](https://openapi-generator.tech).
## Requirements
- [Terraform](https://www.terraform.io/downloads.html) >= 1.0
- [Go](https://golang.org/doc/install) >= 1.22
## Building The Provider
1. Clone the repository
2. Enter the repository directory
3. Build the provider using the Go `install` command:
```shell
go install
```
## Using the provider
```hcl
terraform {
required_providers {
oneof = {
source = "registry.terraform.io/example/oneof-disc"
}
}
}
provider "oneof" {
endpoint = "http://localhost"
}
```
## Developing the Provider
If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above).
To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.
For local development and testing, add a `dev_overrides` block to your `~/.terraformrc` so that Terraform uses the locally built binary instead of fetching from the registry:
```hcl
provider_installation {
dev_overrides {
"registry.terraform.io/example/oneof-disc" = "${GOPATH}/bin"
}
direct {}
}
```
With `dev_overrides` configured, you do not need to run `terraform init` for the provider.
To generate or update documentation, run `go generate`.
In order to run the full suite of Acceptance tests, run `make testacc`.
```shell
make testacc
```

View File

@@ -0,0 +1,13 @@
terraform {
required_providers {
oneof = {
source = "registry.terraform.io/example/oneof-disc"
}
}
}
provider "oneof" {
endpoint = "http://localhost"
# api_key = "your-api-key"
# token = "your-bearer-token"
}

View File

@@ -0,0 +1,11 @@
module github.com/example/terraform-provider-oneof-disc
go 1.24.0
toolchain go1.24.4
require (
github.com/hashicorp/terraform-plugin-framework v1.17.0
github.com/hashicorp/terraform-plugin-log v0.10.0
github.com/hashicorp/terraform-plugin-testing v1.14.0
)

View File

@@ -0,0 +1,99 @@
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-framework v1.17.0 h1:JdX50CFrYcYFY31gkmitAEAzLKoBgsK+iaJjDC8OexY=
github.com/hashicorp/terraform-plugin-framework v1.17.0/go.mod h1:4OUXKdHNosX+ys6rLgVlgklfxN3WHR5VHSOABeS/BM0=
github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
github.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,78 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
// Client is the API client used to interact with the API.
type Client struct {
BaseURL string
HTTPClient *http.Client
ApiKey string
Token string
Username string
Password string
}
// NewClient creates a new API client with the given base URL.
func NewClient(baseURL string) *Client {
return &Client{
BaseURL: baseURL,
HTTPClient: &http.Client{},
}
}
// DoRequest executes an HTTP request and returns the response body.
func (c *Client) DoRequest(ctx context.Context, method, path string, body interface{}) ([]byte, error) {
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("error marshaling request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequestWithContext(ctx, method, c.BaseURL+path, reqBody)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
// Authentication
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
} else if c.ApiKey != "" {
req.Header.Set("Authorization", c.ApiKey)
} else if c.Username != "" {
req.SetBasicAuth(c.Username, c.Password)
}
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(respBody))
}
return respBody, nil
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// NestedObject1 - NestedObject1 struct
type NestedObject1 struct {
Field1 string `json:"field1"`
Type string `json:"type,omitempty"`
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// NestedObject2 - NestedObject2 struct
type NestedObject2 struct {
Field1 string `json:"field1,omitempty"`
Type string `json:"type,omitempty"`
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// Object - Object struct
type Object struct {
Field1 string `json:"field1"`
Type string `json:"type,omitempty"`
}

View File

@@ -0,0 +1,121 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package provider
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/example/terraform-provider-oneof-disc/internal/client"
)
var _ provider.Provider = &oneofProvider{}
type oneofProvider struct {
version string
}
type oneofProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`
ApiKey types.String `tfsdk:"api_key"`
Token types.String `tfsdk:"token"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &oneofProvider{
version: version,
}
}
}
func (p *oneofProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "oneof"
resp.Version = p.version
}
func (p *oneofProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"endpoint": schema.StringAttribute{
Optional: true,
Description: "The API endpoint URL.",
},
"api_key": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The API key for authentication.",
},
"token": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The bearer token for authentication.",
},
"username": schema.StringAttribute{
Optional: true,
Description: "The username for basic authentication.",
},
"password": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The password for basic authentication.",
},
},
}
}
func (p *oneofProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var config oneofProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
if config.Endpoint.IsUnknown() {
resp.Diagnostics.AddWarning(
"Unknown Endpoint Value",
"The provider endpoint value is not yet known. Defaulting to the spec-defined base path.",
)
}
endpoint := "http://localhost"
if !config.Endpoint.IsNull() && !config.Endpoint.IsUnknown() {
endpoint = config.Endpoint.ValueString()
}
c := client.NewClient(endpoint)
if !config.ApiKey.IsNull() {
c.ApiKey = config.ApiKey.ValueString()
}
if !config.Token.IsNull() {
c.Token = config.Token.ValueString()
}
if !config.Username.IsNull() {
c.Username = config.Username.ValueString()
}
if !config.Password.IsNull() {
c.Password = config.Password.ValueString()
}
resp.DataSourceData = c
resp.ResourceData = c
}
func (p *oneofProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
}
}
func (p *oneofProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
}
}

View File

@@ -0,0 +1,35 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package main
import (
"context"
"flag"
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/example/terraform-provider-oneof-disc/internal/provider"
)
var (
version string = "0.1.0"
)
func main() {
var debug bool
flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
opts := providerserver.ServeOpts{
Address: "registry.terraform.io/example/oneof-disc",
Debug: debug,
}
err := providerserver.Serve(context.Background(), provider.New(version), opts)
if err != nil {
log.Fatal(err.Error())
}
}

View File

@@ -0,0 +1,13 @@
*.dll
*.exe
*.exe~
*.dylib
*.so
*.test
*.out
*.tfstate
*.tfstate.*
.terraform/
*.tfvars
*.tfvars.json
terraform-provider-petstore

View File

@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@@ -0,0 +1,14 @@
.gitignore
GNUmakefile
README.md
examples/provider/provider.tf
go.mod
internal/client/client.go
internal/client/model_category.go
internal/client/model_pet.go
internal/client/model_tag.go
internal/provider/pet_data_source.go
internal/provider/pet_model.go
internal/provider/pet_resource.go
internal/provider/provider.go
main.go

View File

@@ -0,0 +1 @@
7.20.0-SNAPSHOT

View File

@@ -0,0 +1,27 @@
default: testacc
# Run acceptance tests
.PHONY: testacc
testacc:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
# Build provider
.PHONY: build
build:
go build -o terraform-provider-petstore
# Install provider locally
.PHONY: install
install: build
mkdir -p ~/.terraform.d/plugins/registry.terraform.io/example/petstore-addpet/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)
mv terraform-provider-petstore ~/.terraform.d/plugins/registry.terraform.io/example/petstore-addpet/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)/
# Generate documentation
.PHONY: docs
docs:
go generate ./...
# Run linter
.PHONY: lint
lint:
golangci-lint run ./...

View File

@@ -0,0 +1,61 @@
# Terraform Provider petstore
This Terraform provider was generated using [OpenAPI Generator](https://openapi-generator.tech).
## Requirements
- [Terraform](https://www.terraform.io/downloads.html) >= 1.0
- [Go](https://golang.org/doc/install) >= 1.22
## Building The Provider
1. Clone the repository
2. Enter the repository directory
3. Build the provider using the Go `install` command:
```shell
go install
```
## Using the provider
```hcl
terraform {
required_providers {
petstore = {
source = "registry.terraform.io/example/petstore-addpet"
}
}
}
provider "petstore" {
endpoint = "http://petstore.swagger.io/v2"
}
```
## Developing the Provider
If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above).
To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.
For local development and testing, add a `dev_overrides` block to your `~/.terraformrc` so that Terraform uses the locally built binary instead of fetching from the registry:
```hcl
provider_installation {
dev_overrides {
"registry.terraform.io/example/petstore-addpet" = "${GOPATH}/bin"
}
direct {}
}
```
With `dev_overrides` configured, you do not need to run `terraform init` for the provider.
To generate or update documentation, run `go generate`.
In order to run the full suite of Acceptance tests, run `make testacc`.
```shell
make testacc
```

View File

@@ -0,0 +1,13 @@
terraform {
required_providers {
petstore = {
source = "registry.terraform.io/example/petstore-addpet"
}
}
}
provider "petstore" {
endpoint = "http://petstore.swagger.io/v2"
# api_key = "your-api-key"
# token = "your-bearer-token"
}

View File

@@ -0,0 +1,11 @@
module github.com/example/terraform-provider-petstore-addpet
go 1.24.0
toolchain go1.24.4
require (
github.com/hashicorp/terraform-plugin-framework v1.17.0
github.com/hashicorp/terraform-plugin-log v0.10.0
github.com/hashicorp/terraform-plugin-testing v1.14.0
)

View File

@@ -0,0 +1,99 @@
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-framework v1.17.0 h1:JdX50CFrYcYFY31gkmitAEAzLKoBgsK+iaJjDC8OexY=
github.com/hashicorp/terraform-plugin-framework v1.17.0/go.mod h1:4OUXKdHNosX+ys6rLgVlgklfxN3WHR5VHSOABeS/BM0=
github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
github.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,78 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
// Client is the API client used to interact with the API.
type Client struct {
BaseURL string
HTTPClient *http.Client
ApiKey string
Token string
Username string
Password string
}
// NewClient creates a new API client with the given base URL.
func NewClient(baseURL string) *Client {
return &Client{
BaseURL: baseURL,
HTTPClient: &http.Client{},
}
}
// DoRequest executes an HTTP request and returns the response body.
func (c *Client) DoRequest(ctx context.Context, method, path string, body interface{}) ([]byte, error) {
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("error marshaling request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequestWithContext(ctx, method, c.BaseURL+path, reqBody)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
// Authentication
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
} else if c.ApiKey != "" {
req.Header.Set("Authorization", c.ApiKey)
} else if c.Username != "" {
req.SetBasicAuth(c.Username, c.Password)
}
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(respBody))
}
return respBody, nil
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// Category - A category for a pet
type Category struct {
Id int64 `json:"id,omitempty"`
Name string `json:"name,omitempty" validate:"regexp=^[a-zA-Z0-9]+[a-zA-Z0-9\\\\.\\\\-_]*[a-zA-Z0-9]+$"`
}

View File

@@ -0,0 +1,13 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// Pet - A pet for sale in the pet store
type Pet struct {
Id int64 `json:"id,omitempty"`
Category Category `json:"category,omitempty"`
Name string `json:"name"`
PhotoUrls []string `json:"photoUrls"`
Tags []Tag `json:"tags,omitempty"`
Status string `json:"status,omitempty"`
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// Tag - A tag for a pet
type Tag struct {
Id int64 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}

View File

@@ -0,0 +1,79 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package provider
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/example/terraform-provider-petstore-addpet/internal/client"
)
var _ datasource.DataSource = &PetDataSource{}
func NewPetDataSource() datasource.DataSource {
return &PetDataSource{}
}
type PetDataSource struct {
client *client.Client
}
func (d *PetDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_pet"
}
func (d *PetDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Fetches a pet data source.",
Attributes: map[string]schema.Attribute{
"id": schema.Int64Attribute{
Computed: true,
Description: "",
},
"category": schema.StringAttribute{
Computed: true,
Description: "",
},
"name": schema.StringAttribute{
Required: true,
Description: "",
},
"photo_urls": schema.StringAttribute{
Required: true,
Description: "",
},
"tags": schema.StringAttribute{
Computed: true,
Description: "",
},
"status": schema.StringAttribute{
Computed: true,
Description: "pet status in the store",
},
},
}
}
func (d *PetDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
c, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T.", req.ProviderData),
)
return
}
d.client = c
}
func (d *PetDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
resp.Diagnostics.AddError("Not Supported", "Read is not supported for pet")
}

View File

@@ -0,0 +1,40 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package provider
import (
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/example/terraform-provider-petstore-addpet/internal/client"
)
// PetModel is the Terraform model for pet.
type PetModel struct {
Id types.Int64 `tfsdk:"id"`
Category types.String `tfsdk:"category"`
Name types.String `tfsdk:"name"`
PhotoUrls types.List `tfsdk:"photo_urls"`
Tags types.List `tfsdk:"tags"`
Status types.String `tfsdk:"status"`
}
// ToClientModel converts a Terraform model to a client model.
func (m *PetModel) ToClientModel() *client.Pet {
out := &client.Pet{}
if !m.Id.IsNull() && !m.Id.IsUnknown() {
out.Id = int64(m.Id.ValueInt64())
}
if !m.Name.IsNull() && !m.Name.IsUnknown() {
out.Name = m.Name.ValueString()
}
if !m.Status.IsNull() && !m.Status.IsUnknown() {
out.Status = m.Status.ValueString()
}
return out
}
// FromClientModel updates the Terraform model from a client model.
func (m *PetModel) FromClientModel(c *client.Pet) {
m.Id = types.Int64Value(int64(c.Id))
m.Name = types.StringValue(c.Name)
m.Status = types.StringValue(c.Status)
}

View File

@@ -0,0 +1,136 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package provider
import (
"context"
"fmt"
"encoding/json"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/example/terraform-provider-petstore-addpet/internal/client"
)
var _ resource.Resource = &PetResource{}
var _ resource.ResourceWithImportState = &PetResource{}
func NewPetResource() resource.Resource {
return &PetResource{}
}
type PetResource struct {
client *client.Client
}
func (r *PetResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_pet"
}
func (r *PetResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Manages a pet resource.",
Attributes: map[string]schema.Attribute{
"id": schema.Int64Attribute{
Optional: true,
Description: "",
},
"category": schema.StringAttribute{
Optional: true,
Description: "",
},
"name": schema.StringAttribute{
Required: true,
Description: "",
},
"photo_urls": schema.ListAttribute{
Required: true,
ElementType: types.StringType,
Description: "",
},
"tags": schema.ListAttribute{
Optional: true,
ElementType: types.StringType,
Description: "",
},
"status": schema.StringAttribute{
Optional: true,
Description: "pet status in the store",
},
},
}
}
func (r *PetResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
c, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T.", req.ProviderData),
)
return
}
r.client = c
}
func (r *PetResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan PetModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
reqBody := plan.ToClientModel()
respBody, err := r.client.DoRequest(ctx, "POST", "/pet", reqBody)
if err != nil {
resp.Diagnostics.AddError("Error creating pet", err.Error())
return
}
var result client.Pet
if err := json.Unmarshal(respBody, &result); err != nil {
resp.Diagnostics.AddError("Error parsing response", err.Error())
return
}
plan.FromClientModel(&result)
tflog.Trace(ctx, "created pet resource")
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}
func (r *PetResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// No read endpoint available; keep existing state as-is.
}
func (r *PetResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
// No update endpoint available; persist the planned values into state.
var plan PetModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}
func (r *PetResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
// No delete endpoint available; remove the resource from state.
}
func (r *PetResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

View File

@@ -0,0 +1,123 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package provider
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/example/terraform-provider-petstore-addpet/internal/client"
)
var _ provider.Provider = &petstoreProvider{}
type petstoreProvider struct {
version string
}
type petstoreProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`
ApiKey types.String `tfsdk:"api_key"`
Token types.String `tfsdk:"token"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &petstoreProvider{
version: version,
}
}
}
func (p *petstoreProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "petstore"
resp.Version = p.version
}
func (p *petstoreProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"endpoint": schema.StringAttribute{
Optional: true,
Description: "The API endpoint URL.",
},
"api_key": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The API key for authentication.",
},
"token": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The bearer token for authentication.",
},
"username": schema.StringAttribute{
Optional: true,
Description: "The username for basic authentication.",
},
"password": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "The password for basic authentication.",
},
},
}
}
func (p *petstoreProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var config petstoreProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
if config.Endpoint.IsUnknown() {
resp.Diagnostics.AddWarning(
"Unknown Endpoint Value",
"The provider endpoint value is not yet known. Defaulting to the spec-defined base path.",
)
}
endpoint := "http://petstore.swagger.io/v2"
if !config.Endpoint.IsNull() && !config.Endpoint.IsUnknown() {
endpoint = config.Endpoint.ValueString()
}
c := client.NewClient(endpoint)
if !config.ApiKey.IsNull() {
c.ApiKey = config.ApiKey.ValueString()
}
if !config.Token.IsNull() {
c.Token = config.Token.ValueString()
}
if !config.Username.IsNull() {
c.Username = config.Username.ValueString()
}
if !config.Password.IsNull() {
c.Password = config.Password.ValueString()
}
resp.DataSourceData = c
resp.ResourceData = c
}
func (p *petstoreProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
NewPetResource,
}
}
func (p *petstoreProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
NewPetDataSource,
}
}

View File

@@ -0,0 +1,35 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package main
import (
"context"
"flag"
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/example/terraform-provider-petstore-addpet/internal/provider"
)
var (
version string = "0.1.0"
)
func main() {
var debug bool
flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
opts := providerserver.ServeOpts{
Address: "registry.terraform.io/example/petstore-addpet",
Debug: debug,
}
err := providerserver.Serve(context.Background(), provider.New(version), opts)
if err != nil {
log.Fatal(err.Error())
}
}

View File

@@ -0,0 +1,13 @@
*.dll
*.exe
*.exe~
*.dylib
*.so
*.test
*.out
*.tfstate
*.tfstate.*
.terraform/
*.tfvars
*.tfvars.json
terraform-provider-petstore

View File

@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@@ -0,0 +1,33 @@
.gitignore
GNUmakefile
README.md
examples/provider/provider.tf
go.mod
internal/client/client.go
internal/client/model_an_object.go
internal/client/model_api_response.go
internal/client/model_category.go
internal/client/model_colour.go
internal/client/model_gender.go
internal/client/model_order.go
internal/client/model_order_info.go
internal/client/model_pet.go
internal/client/model_special_info.go
internal/client/model_species.go
internal/client/model_tag.go
internal/client/model_user.go
internal/client/model_user_nullable.go
internal/provider/fake_data_source.go
internal/provider/fake_model.go
internal/provider/fake_resource.go
internal/provider/pet_data_source.go
internal/provider/pet_model.go
internal/provider/pet_resource.go
internal/provider/provider.go
internal/provider/store_data_source.go
internal/provider/store_model.go
internal/provider/store_resource.go
internal/provider/user_data_source.go
internal/provider/user_model.go
internal/provider/user_resource.go
main.go

View File

@@ -0,0 +1 @@
7.20.0-SNAPSHOT

View File

@@ -0,0 +1,27 @@
default: testacc
# Run acceptance tests
.PHONY: testacc
testacc:
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
# Build provider
.PHONY: build
build:
go build -o terraform-provider-petstore
# Install provider locally
.PHONY: install
install: build
mkdir -p ~/.terraform.d/plugins/registry.terraform.io/example/petstore-server/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)
mv terraform-provider-petstore ~/.terraform.d/plugins/registry.terraform.io/example/petstore-server/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH)/
# Generate documentation
.PHONY: docs
docs:
go generate ./...
# Run linter
.PHONY: lint
lint:
golangci-lint run ./...

View File

@@ -0,0 +1,61 @@
# Terraform Provider petstore
This Terraform provider was generated using [OpenAPI Generator](https://openapi-generator.tech).
## Requirements
- [Terraform](https://www.terraform.io/downloads.html) >= 1.0
- [Go](https://golang.org/doc/install) >= 1.22
## Building The Provider
1. Clone the repository
2. Enter the repository directory
3. Build the provider using the Go `install` command:
```shell
go install
```
## Using the provider
```hcl
terraform {
required_providers {
petstore = {
source = "registry.terraform.io/example/petstore-server"
}
}
}
provider "petstore" {
endpoint = "http://petstore.swagger.io/v2"
}
```
## Developing the Provider
If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above).
To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.
For local development and testing, add a `dev_overrides` block to your `~/.terraformrc` so that Terraform uses the locally built binary instead of fetching from the registry:
```hcl
provider_installation {
dev_overrides {
"registry.terraform.io/example/petstore-server" = "${GOPATH}/bin"
}
direct {}
}
```
With `dev_overrides` configured, you do not need to run `terraform init` for the provider.
To generate or update documentation, run `go generate`.
In order to run the full suite of Acceptance tests, run `make testacc`.
```shell
make testacc
```

View File

@@ -0,0 +1,13 @@
terraform {
required_providers {
petstore = {
source = "registry.terraform.io/example/petstore-server"
}
}
}
provider "petstore" {
endpoint = "http://petstore.swagger.io/v2"
# api_key = "your-api-key"
# token = "your-bearer-token"
}

View File

@@ -0,0 +1,11 @@
module github.com/example/terraform-provider-petstore-server
go 1.24.0
toolchain go1.24.4
require (
github.com/hashicorp/terraform-plugin-framework v1.17.0
github.com/hashicorp/terraform-plugin-log v0.10.0
github.com/hashicorp/terraform-plugin-testing v1.14.0
)

View File

@@ -0,0 +1,99 @@
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-framework v1.17.0 h1:JdX50CFrYcYFY31gkmitAEAzLKoBgsK+iaJjDC8OexY=
github.com/hashicorp/terraform-plugin-framework v1.17.0/go.mod h1:4OUXKdHNosX+ys6rLgVlgklfxN3WHR5VHSOABeS/BM0=
github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
github.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,78 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
// Client is the API client used to interact with the API.
type Client struct {
BaseURL string
HTTPClient *http.Client
ApiKey string
Token string
Username string
Password string
}
// NewClient creates a new API client with the given base URL.
func NewClient(baseURL string) *Client {
return &Client{
BaseURL: baseURL,
HTTPClient: &http.Client{},
}
}
// DoRequest executes an HTTP request and returns the response body.
func (c *Client) DoRequest(ctx context.Context, method, path string, body interface{}) ([]byte, error) {
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("error marshaling request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequestWithContext(ctx, method, c.BaseURL+path, reqBody)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
// Authentication
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
} else if c.ApiKey != "" {
req.Header.Set("Authorization", c.ApiKey)
} else if c.Username != "" {
req.SetBasicAuth(c.Username, c.Password)
}
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(respBody))
}
return respBody, nil
}

View File

@@ -0,0 +1,9 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package client
// AnObject - An array 3-deep.
type AnObject struct {
Tag Tag `json:"tag,omitempty"`
Pet []Pet `json:"Pet,omitempty"`
}

Some files were not shown because too many files have changed in this diff Show More