From ad46e19bd77a2d19ae839910e3cdc4f1385f1fc7 Mon Sep 17 00:00:00 2001 From: Jason D'Amour Date: Thu, 12 Feb 2026 05:39:26 +0000 Subject: [PATCH 1/7] [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 --- .../languages/TerraformProviderCodegen.java | 541 ++++++++++++++++++ .../org.openapitools.codegen.CodegenConfig | 1 + .../terraform-provider/GNUmakefile.mustache | 27 + .../terraform-provider/README.mustache | 48 ++ .../terraform-provider/client.mustache | 77 +++ .../terraform-provider/data_source.mustache | 108 ++++ .../terraform-provider/gitignore.mustache | 12 + .../terraform-provider/go.mod.mustache | 11 + .../terraform-provider/main.mustache | 34 ++ .../terraform-provider/model.mustache | 13 + .../partial_header.mustache | 1 + .../terraform-provider/provider.mustache | 115 ++++ .../provider_example.mustache | 13 + .../terraform-provider/resource.mustache | 241 ++++++++ .../resource_model.mustache | 67 +++ .../TerraformProviderCodegenTest.java | 180 ++++++ 16 files changed, 1489 insertions(+) create mode 100644 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TerraformProviderCodegen.java create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/GNUmakefile.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/README.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/client.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/data_source.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/gitignore.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/go.mod.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/main.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/model.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/partial_header.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/provider.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/provider_example.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/resource.mustache create mode 100644 modules/openapi-generator/src/main/resources/terraform-provider/resource_model.mustache create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/terraform/provider/TerraformProviderCodegenTest.java diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TerraformProviderCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TerraformProviderCodegen.java new file mode 100644 index 000000000000..ec3994842678 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TerraformProviderCodegen.java @@ -0,0 +1,541 @@ +/* + * 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 allModels) { + OperationMap objectMap = objs.getOperations(); + List 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> tfAttributes = new ArrayList<>(); + boolean hasListAttributes = false; + for (CodegenProperty prop : model.vars) { + Map 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) { + // 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)); + } +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 345f9b2543b7..ccfd6366994b 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -148,6 +148,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 diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/GNUmakefile.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/GNUmakefile.mustache new file mode 100644 index 000000000000..341d3d1a573d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/GNUmakefile.mustache @@ -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 ./... diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache new file mode 100644 index 000000000000..2293329bef39 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache @@ -0,0 +1,48 @@ +# 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.21 + +## 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. + +To generate or update documentation, run `go generate`. + +In order to run the full suite of Acceptance tests, run `make testacc`. + +```shell +make testacc +``` diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/client.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/client.mustache new file mode 100644 index 000000000000..ca744552d861 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/client.mustache @@ -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 +} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/data_source.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/data_source.mustache new file mode 100644 index 000000000000..4c6131168153 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/data_source.mustache @@ -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}} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/gitignore.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/gitignore.mustache new file mode 100644 index 000000000000..1fd3996fcff0 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/gitignore.mustache @@ -0,0 +1,12 @@ +*.dll +*.exe +*.exe~ +*.dylib +*.so +*.test +*.out +*.tfstate +*.tfstate.* +.terraform/ +terraform.tfvars +terraform-provider-{{providerName}} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/go.mod.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/go.mod.mustache new file mode 100644 index 000000000000..67e36d995851 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/go.mod.mustache @@ -0,0 +1,11 @@ +module {{gitHost}}/{{gitUserId}}/{{gitRepoId}} + +go 1.22 + +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 +) diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/main.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/main.mustache new file mode 100644 index 000000000000..38b01dc6c8fb --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/main.mustache @@ -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()) + } +} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/model.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/model.mustache new file mode 100644 index 000000000000..4bb56a40153b --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/model.mustache @@ -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}} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/partial_header.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/partial_header.mustache new file mode 100644 index 000000000000..df685adbc68e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/partial_header.mustache @@ -0,0 +1 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/provider.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/provider.mustache new file mode 100644 index 000000000000..3628c3d0d223 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/provider.mustache @@ -0,0 +1,115 @@ +{{>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 + } + + endpoint := config.Endpoint.ValueString() + if endpoint == "" { + endpoint = "{{{basePath}}}" + } + + 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}} } +} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/provider_example.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/provider_example.mustache new file mode 100644 index 000000000000..0c7cfdb143be --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/provider_example.mustache @@ -0,0 +1,13 @@ +terraform { + required_providers { + {{providerName}} = { + source = "{{providerAddress}}" + } + } +} + +provider "{{providerName}}" { + endpoint = "{{{basePath}}}" + # api_key = "your-api-key" + # token = "your-bearer-token" +} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/resource.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/resource.mustache new file mode 100644 index 000000000000..e5fd5b6b454d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/resource.mustache @@ -0,0 +1,241 @@ +{{#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) { + resp.Diagnostics.AddError("Not Supported", "Read is not supported for {{resourceName}}") +} +{{/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) { + resp.Diagnostics.AddError("Not Supported", "Update is not supported for {{resourceName}}") +} +{{/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) { + resp.Diagnostics.AddError("Not Supported", "Delete is not supported for {{resourceName}}") +} +{{/hasDelete}} + +func (r *{{resourceClassName}}Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("{{idFieldTerraformName}}"), req, resp) +} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/resource_model.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/resource_model.mustache new file mode 100644 index 000000000000..4ad9ec21de5a --- /dev/null +++ b/modules/openapi-generator/src/main/resources/terraform-provider/resource_model.mustache @@ -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}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/terraform/provider/TerraformProviderCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/terraform/provider/TerraformProviderCodegenTest.java new file mode 100644 index 000000000000..ecb86411ac22 --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/terraform/provider/TerraformProviderCodegenTest.java @@ -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 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 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 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 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 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 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"); + } +} From 50b9cdd233110c9acf454aa064fd430e16ef1e32 Mon Sep 17 00:00:00 2001 From: Jason D'Amour Date: Thu, 12 Feb 2026 05:39:41 +0000 Subject: [PATCH 2/7] [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 --- .../terraform-provider-petstore-new.yaml | 11 + samples/client/petstore/terraform/.gitignore | 12 + .../terraform/.openapi-generator-ignore | 23 ++ .../terraform/.openapi-generator/FILES | 23 ++ .../terraform/.openapi-generator/VERSION | 1 + samples/client/petstore/terraform/GNUmakefile | 27 ++ samples/client/petstore/terraform/README.md | 48 ++++ .../examples/data-sources/pet/data-source.tf | 8 + .../examples/data-sources/user/data-source.tf | 7 + .../terraform/examples/provider/provider.tf | 13 + .../examples/resources/pet/resource.tf | 5 + .../examples/resources/user/resource.tf | 8 + samples/client/petstore/terraform/go.mod | 64 +++++ samples/client/petstore/terraform/go.sum | 241 ++++++++++++++++++ .../terraform/internal/client/client.go | 78 ++++++ .../internal/client/model_api_response.go | 10 + .../internal/client/model_category.go | 9 + .../terraform/internal/client/model_order.go | 13 + .../terraform/internal/client/model_pet.go | 13 + .../terraform/internal/client/model_tag.go | 9 + .../terraform/internal/client/model_user.go | 15 ++ .../internal/provider/pet_data_source.go | 103 ++++++++ .../terraform/internal/provider/pet_model.go | 40 +++ .../internal/provider/pet_resource.go | 164 ++++++++++++ .../internal/provider/pet_resource_test.go | 59 +++++ .../terraform/internal/provider/provider.go | 120 +++++++++ .../internal/provider/provider_test.go | 19 ++ .../internal/provider/store_data_source.go | 55 ++++ .../internal/provider/store_model.go | 8 + .../internal/provider/store_resource.go | 77 ++++++ .../internal/provider/user_data_source.go | 111 ++++++++ .../terraform/internal/provider/user_model.go | 62 +++++ .../internal/provider/user_resource.go | 193 ++++++++++++++ .../internal/provider/user_resource_test.go | 93 +++++++ samples/client/petstore/terraform/main.go | 35 +++ 35 files changed, 1777 insertions(+) create mode 100644 bin/configs/terraform-provider-petstore-new.yaml create mode 100644 samples/client/petstore/terraform/.gitignore create mode 100644 samples/client/petstore/terraform/.openapi-generator-ignore create mode 100644 samples/client/petstore/terraform/.openapi-generator/FILES create mode 100644 samples/client/petstore/terraform/.openapi-generator/VERSION create mode 100644 samples/client/petstore/terraform/GNUmakefile create mode 100644 samples/client/petstore/terraform/README.md create mode 100644 samples/client/petstore/terraform/examples/data-sources/pet/data-source.tf create mode 100644 samples/client/petstore/terraform/examples/data-sources/user/data-source.tf create mode 100644 samples/client/petstore/terraform/examples/provider/provider.tf create mode 100644 samples/client/petstore/terraform/examples/resources/pet/resource.tf create mode 100644 samples/client/petstore/terraform/examples/resources/user/resource.tf create mode 100644 samples/client/petstore/terraform/go.mod create mode 100644 samples/client/petstore/terraform/go.sum create mode 100644 samples/client/petstore/terraform/internal/client/client.go create mode 100644 samples/client/petstore/terraform/internal/client/model_api_response.go create mode 100644 samples/client/petstore/terraform/internal/client/model_category.go create mode 100644 samples/client/petstore/terraform/internal/client/model_order.go create mode 100644 samples/client/petstore/terraform/internal/client/model_pet.go create mode 100644 samples/client/petstore/terraform/internal/client/model_tag.go create mode 100644 samples/client/petstore/terraform/internal/client/model_user.go create mode 100644 samples/client/petstore/terraform/internal/provider/pet_data_source.go create mode 100644 samples/client/petstore/terraform/internal/provider/pet_model.go create mode 100644 samples/client/petstore/terraform/internal/provider/pet_resource.go create mode 100644 samples/client/petstore/terraform/internal/provider/pet_resource_test.go create mode 100644 samples/client/petstore/terraform/internal/provider/provider.go create mode 100644 samples/client/petstore/terraform/internal/provider/provider_test.go create mode 100644 samples/client/petstore/terraform/internal/provider/store_data_source.go create mode 100644 samples/client/petstore/terraform/internal/provider/store_model.go create mode 100644 samples/client/petstore/terraform/internal/provider/store_resource.go create mode 100644 samples/client/petstore/terraform/internal/provider/user_data_source.go create mode 100644 samples/client/petstore/terraform/internal/provider/user_model.go create mode 100644 samples/client/petstore/terraform/internal/provider/user_resource.go create mode 100644 samples/client/petstore/terraform/internal/provider/user_resource_test.go create mode 100644 samples/client/petstore/terraform/main.go diff --git a/bin/configs/terraform-provider-petstore-new.yaml b/bin/configs/terraform-provider-petstore-new.yaml new file mode 100644 index 000000000000..d0be301e0d19 --- /dev/null +++ b/bin/configs/terraform-provider-petstore-new.yaml @@ -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" diff --git a/samples/client/petstore/terraform/.gitignore b/samples/client/petstore/terraform/.gitignore new file mode 100644 index 000000000000..f2e3600d79b0 --- /dev/null +++ b/samples/client/petstore/terraform/.gitignore @@ -0,0 +1,12 @@ +*.dll +*.exe +*.exe~ +*.dylib +*.so +*.test +*.out +*.tfstate +*.tfstate.* +.terraform/ +terraform.tfvars +terraform-provider-petstore diff --git a/samples/client/petstore/terraform/.openapi-generator-ignore b/samples/client/petstore/terraform/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/client/petstore/terraform/.openapi-generator-ignore @@ -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 diff --git a/samples/client/petstore/terraform/.openapi-generator/FILES b/samples/client/petstore/terraform/.openapi-generator/FILES new file mode 100644 index 000000000000..219ca57a71ef --- /dev/null +++ b/samples/client/petstore/terraform/.openapi-generator/FILES @@ -0,0 +1,23 @@ +.gitignore +GNUmakefile +README.md +examples/provider/provider.tf +go.mod +internal/client/client.go +internal/client/model_api_response.go +internal/client/model_category.go +internal/client/model_order.go +internal/client/model_pet.go +internal/client/model_tag.go +internal/client/model_user.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 diff --git a/samples/client/petstore/terraform/.openapi-generator/VERSION b/samples/client/petstore/terraform/.openapi-generator/VERSION new file mode 100644 index 000000000000..193a12d6e891 --- /dev/null +++ b/samples/client/petstore/terraform/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.20.0-SNAPSHOT diff --git a/samples/client/petstore/terraform/GNUmakefile b/samples/client/petstore/terraform/GNUmakefile new file mode 100644 index 000000000000..685e3c9b2449 --- /dev/null +++ b/samples/client/petstore/terraform/GNUmakefile @@ -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/0.1.0/$(shell go env GOOS)_$(shell go env GOARCH) + mv terraform-provider-petstore ~/.terraform.d/plugins/registry.terraform.io/example/petstore/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 ./... diff --git a/samples/client/petstore/terraform/README.md b/samples/client/petstore/terraform/README.md new file mode 100644 index 000000000000..cab12402edc5 --- /dev/null +++ b/samples/client/petstore/terraform/README.md @@ -0,0 +1,48 @@ +# 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.21 + +## 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" + } + } +} + +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. + +To generate or update documentation, run `go generate`. + +In order to run the full suite of Acceptance tests, run `make testacc`. + +```shell +make testacc +``` diff --git a/samples/client/petstore/terraform/examples/data-sources/pet/data-source.tf b/samples/client/petstore/terraform/examples/data-sources/pet/data-source.tf new file mode 100644 index 000000000000..dfcbdb90bcb0 --- /dev/null +++ b/samples/client/petstore/terraform/examples/data-sources/pet/data-source.tf @@ -0,0 +1,8 @@ +data "petstore_pet" "example" { + name = "fido" + photo_urls = "https://example.com/fido.jpg" +} + +output "pet_status" { + value = data.petstore_pet.example.status +} diff --git a/samples/client/petstore/terraform/examples/data-sources/user/data-source.tf b/samples/client/petstore/terraform/examples/data-sources/user/data-source.tf new file mode 100644 index 000000000000..0ded06531e87 --- /dev/null +++ b/samples/client/petstore/terraform/examples/data-sources/user/data-source.tf @@ -0,0 +1,7 @@ +data "petstore_user" "example" { + username = "johndoe" +} + +output "user_email" { + value = data.petstore_user.example.email +} diff --git a/samples/client/petstore/terraform/examples/provider/provider.tf b/samples/client/petstore/terraform/examples/provider/provider.tf new file mode 100644 index 000000000000..79cc30d2e4e7 --- /dev/null +++ b/samples/client/petstore/terraform/examples/provider/provider.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + petstore = { + source = "registry.terraform.io/example/petstore" + } + } +} + +provider "petstore" { + endpoint = "http://petstore.swagger.io/v2" + # api_key = "your-api-key" + # token = "your-bearer-token" +} diff --git a/samples/client/petstore/terraform/examples/resources/pet/resource.tf b/samples/client/petstore/terraform/examples/resources/pet/resource.tf new file mode 100644 index 000000000000..75e0b92fdcc4 --- /dev/null +++ b/samples/client/petstore/terraform/examples/resources/pet/resource.tf @@ -0,0 +1,5 @@ +resource "petstore_pet" "example" { + name = "fido" + status = "available" + photo_urls = ["https://example.com/fido.jpg"] +} diff --git a/samples/client/petstore/terraform/examples/resources/user/resource.tf b/samples/client/petstore/terraform/examples/resources/user/resource.tf new file mode 100644 index 000000000000..a74edec24914 --- /dev/null +++ b/samples/client/petstore/terraform/examples/resources/user/resource.tf @@ -0,0 +1,8 @@ +resource "petstore_user" "example" { + username = "johndoe" + first_name = "John" + last_name = "Doe" + email = "john@example.com" + password = "secret123" + phone = "555-1234" +} diff --git a/samples/client/petstore/terraform/go.mod b/samples/client/petstore/terraform/go.mod new file mode 100644 index 000000000000..570887906ac9 --- /dev/null +++ b/samples/client/petstore/terraform/go.mod @@ -0,0 +1,64 @@ +module github.com/example/terraform-provider-petstore + +go 1.24.0 + +toolchain go1.24.4 + +require ( + github.com/hashicorp/terraform-plugin-framework v1.17.0 + github.com/hashicorp/terraform-plugin-go v0.29.0 + github.com/hashicorp/terraform-plugin-log v0.10.0 + github.com/hashicorp/terraform-plugin-testing v1.14.0 +) + +require ( + github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/agext/levenshtein v1.2.2 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/cloudflare/circl v1.6.1 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-checkpoint v0.5.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-cty v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.7.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/hashicorp/hc-install v0.9.2 // indirect + github.com/hashicorp/hcl/v2 v2.24.0 // indirect + github.com/hashicorp/logutils v1.0.0 // indirect + github.com/hashicorp/terraform-exec v0.24.0 // indirect + github.com/hashicorp/terraform-json v0.27.2 // indirect + github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 // indirect + github.com/hashicorp/terraform-registry-address v0.4.0 // indirect + github.com/hashicorp/terraform-svchost v0.1.1 // indirect + github.com/hashicorp/yamux v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/zclconf/go-cty v1.17.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/tools v0.38.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/grpc v1.75.1 // indirect + google.golang.org/protobuf v1.36.9 // indirect +) diff --git a/samples/client/petstore/terraform/go.sum b/samples/client/petstore/terraform/go.sum new file mode 100644 index 000000000000..9067c4eb87bd --- /dev/null +++ b/samples/client/petstore/terraform/go.sum @@ -0,0 +1,241 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= +github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +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/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +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/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +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-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= +github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= +github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= +github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= +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/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= +github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-cty v1.5.0 h1:EkQ/v+dDNUqnuVpmS5fPqyY71NXVgT5gf32+57xY8g0= +github.com/hashicorp/go-cty v1.5.0/go.mod h1:lFUCG5kd8exDobgSfyj4ONE/dc822kiYMguVKdHGMLM= +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-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +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-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +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/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24= +github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I= +github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE= +github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/terraform-exec v0.24.0 h1:mL0xlk9H5g2bn0pPF6JQZk5YlByqSqrO5VoaNtAf8OE= +github.com/hashicorp/terraform-exec v0.24.0/go.mod h1:lluc/rDYfAhYdslLJQg3J0oDqo88oGQAdHR+wDqFvo4= +github.com/hashicorp/terraform-json v0.27.2 h1:BwGuzM6iUPqf9JYM/Z4AF1OJ5VVJEEzoKST/tRDBJKU= +github.com/hashicorp/terraform-json v0.27.2/go.mod h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE= +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-plugin-sdk/v2 v2.38.1 h1:mlAq/OrMlg04IuJT7NpefI1wwtdpWudnEmjuQs04t/4= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1/go.mod h1:GQhpKVvvuwzD79e8/NZ+xzj+ZpWovdPAe8nfV/skwNU= +github.com/hashicorp/terraform-plugin-testing v1.14.0 h1:5t4VKrjOJ0rg0sVuSJ86dz5K7PHsMO6OKrHFzDBerWA= +github.com/hashicorp/terraform-plugin-testing v1.14.0/go.mod h1:1qfWkecyYe1Do2EEOK/5/WnTyvC8wQucUkkhiGLg5nk= +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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +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/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +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/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +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/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +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/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= +github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +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/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= +github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= +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 v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +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= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zclconf/go-cty v1.17.0 h1:seZvECve6XX4tmnvRzWtJNHdscMtYEx5R7bnnVyd/d0= +github.com/zclconf/go-cty v1.17.0/go.mod h1:wqFzcImaLTI6A5HfsRwB0nj5n0MRZFwmey8YoFPPs3U= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= +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/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +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.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +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/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/samples/client/petstore/terraform/internal/client/client.go b/samples/client/petstore/terraform/internal/client/client.go new file mode 100644 index 000000000000..247e45a1c730 --- /dev/null +++ b/samples/client/petstore/terraform/internal/client/client.go @@ -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 +} diff --git a/samples/client/petstore/terraform/internal/client/model_api_response.go b/samples/client/petstore/terraform/internal/client/model_api_response.go new file mode 100644 index 000000000000..8512ff6a6f5c --- /dev/null +++ b/samples/client/petstore/terraform/internal/client/model_api_response.go @@ -0,0 +1,10 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// ApiResponse - Describes the result of uploading an image resource +type ApiResponse struct { + Code int32 `json:"code,omitempty"` + Type string `json:"type,omitempty"` + Message string `json:"message,omitempty"` +} diff --git a/samples/client/petstore/terraform/internal/client/model_category.go b/samples/client/petstore/terraform/internal/client/model_category.go new file mode 100644 index 000000000000..1813ce260524 --- /dev/null +++ b/samples/client/petstore/terraform/internal/client/model_category.go @@ -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]+$"` +} diff --git a/samples/client/petstore/terraform/internal/client/model_order.go b/samples/client/petstore/terraform/internal/client/model_order.go new file mode 100644 index 000000000000..9b259e1de869 --- /dev/null +++ b/samples/client/petstore/terraform/internal/client/model_order.go @@ -0,0 +1,13 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// Order - An order for a pets from the pet store +type Order struct { + Id int64 `json:"id,omitempty"` + PetId int64 `json:"petId,omitempty"` + Quantity int32 `json:"quantity,omitempty"` + ShipDate string `json:"shipDate,omitempty"` + Status string `json:"status,omitempty"` + Complete bool `json:"complete,omitempty"` +} diff --git a/samples/client/petstore/terraform/internal/client/model_pet.go b/samples/client/petstore/terraform/internal/client/model_pet.go new file mode 100644 index 000000000000..96e95cec74c7 --- /dev/null +++ b/samples/client/petstore/terraform/internal/client/model_pet.go @@ -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"` +} diff --git a/samples/client/petstore/terraform/internal/client/model_tag.go b/samples/client/petstore/terraform/internal/client/model_tag.go new file mode 100644 index 000000000000..6e81eb958ae7 --- /dev/null +++ b/samples/client/petstore/terraform/internal/client/model_tag.go @@ -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"` +} diff --git a/samples/client/petstore/terraform/internal/client/model_user.go b/samples/client/petstore/terraform/internal/client/model_user.go new file mode 100644 index 000000000000..db3f822931ec --- /dev/null +++ b/samples/client/petstore/terraform/internal/client/model_user.go @@ -0,0 +1,15 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// User - A User who is purchasing from the pet store +type User struct { + Id int64 `json:"id,omitempty"` + Username string `json:"username,omitempty"` + FirstName string `json:"firstName,omitempty"` + LastName string `json:"lastName,omitempty"` + Email string `json:"email,omitempty"` + Password string `json:"password,omitempty"` + Phone string `json:"phone,omitempty"` + UserStatus int32 `json:"userStatus,omitempty"` +} diff --git a/samples/client/petstore/terraform/internal/provider/pet_data_source.go b/samples/client/petstore/terraform/internal/provider/pet_data_source.go new file mode 100644 index 000000000000..d5ea1ecc2a67 --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/pet_data_source.go @@ -0,0 +1,103 @@ +// 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/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-log/tflog" + + "github.com/example/terraform-provider-petstore/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) { + var config PetModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + respBody, err := d.client.DoRequest(ctx, "GET", fmt.Sprintf("/pet/%v", config.Id.ValueInt64()), nil) + if err != nil { + resp.Diagnostics.AddError("Error reading 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 + } + + config.FromClientModel(&result) + + tflog.Trace(ctx, "read pet data source") + resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) +} diff --git a/samples/client/petstore/terraform/internal/provider/pet_model.go b/samples/client/petstore/terraform/internal/provider/pet_model.go new file mode 100644 index 000000000000..7b6836431f94 --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/pet_model.go @@ -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/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) +} diff --git a/samples/client/petstore/terraform/internal/provider/pet_resource.go b/samples/client/petstore/terraform/internal/provider/pet_resource.go new file mode 100644 index 000000000000..6b4667ec3eec --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/pet_resource.go @@ -0,0 +1,164 @@ +// 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/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) { + var state PetModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + respBody, err := r.client.DoRequest(ctx, "GET", fmt.Sprintf("/pet/%v", state.Id.ValueInt64()), nil) + if err != nil { + resp.Diagnostics.AddError("Error reading 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 + } + + state.FromClientModel(&result) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *PetResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Not Supported", "Update is not supported for pet") +} + +func (r *PetResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state PetModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.DoRequest(ctx, "DELETE", fmt.Sprintf("/pet/%v", state.Id.ValueInt64()), nil) + if err != nil { + resp.Diagnostics.AddError("Error deleting pet", err.Error()) + return + } + + tflog.Trace(ctx, "deleted pet resource") +} + +func (r *PetResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/samples/client/petstore/terraform/internal/provider/pet_resource_test.go b/samples/client/petstore/terraform/internal/provider/pet_resource_test.go new file mode 100644 index 000000000000..de73f8c7d883 --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/pet_resource_test.go @@ -0,0 +1,59 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccPetResource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: testAccPetResourceConfig("fido", "available"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("petstore_pet.test", "name", "fido"), + resource.TestCheckResourceAttr("petstore_pet.test", "status", "available"), + resource.TestCheckResourceAttrSet("petstore_pet.test", "id"), + ), + }, + // ImportState testing + { + ResourceName: "petstore_pet.test", + ImportState: true, + ImportStateVerify: true, + }, + // Delete testing is automatically handled by TestCase + }, + }) +} + +func TestAccPetResource_statusPending(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccPetResourceConfig("buddy", "pending"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("petstore_pet.test", "name", "buddy"), + resource.TestCheckResourceAttr("petstore_pet.test", "status", "pending"), + ), + }, + }, + }) +} + +func testAccPetResourceConfig(name string, status string) string { + return fmt.Sprintf(` +%s + +resource "petstore_pet" "test" { + name = %[2]q + status = %[3]q + photo_urls = ["https://example.com/photo.jpg"] +} +`, testAccProviderConfig, name, status) +} diff --git a/samples/client/petstore/terraform/internal/provider/provider.go b/samples/client/petstore/terraform/internal/provider/provider.go new file mode 100644 index 000000000000..108b70ec94dd --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/provider.go @@ -0,0 +1,120 @@ +// 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/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 + } + + endpoint := config.Endpoint.ValueString() + if endpoint == "" { + endpoint = "http://petstore.swagger.io/v2" + } + + 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, + NewStoreResource, + NewUserResource, + } +} + +func (p *petstoreProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + NewPetDataSource, + NewStoreDataSource, + NewUserDataSource, + } +} diff --git a/samples/client/petstore/terraform/internal/provider/provider_test.go b/samples/client/petstore/terraform/internal/provider/provider_test.go new file mode 100644 index 000000000000..27663b792b7a --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/provider_test.go @@ -0,0 +1,19 @@ +package provider + +import ( + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" +) + +// testAccProtoV6ProviderFactories are used to instantiate the provider during +// acceptance testing. The factory function is called for every Terraform CLI +// command executed to create a provider server to which the CLI can reattach. +var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ + "petstore": providerserver.NewProtocol6WithError(New("test")()), +} + +const testAccProviderConfig = ` +provider "petstore" { + endpoint = "http://petstore.swagger.io/v2" +} +` diff --git a/samples/client/petstore/terraform/internal/provider/store_data_source.go b/samples/client/petstore/terraform/internal/provider/store_data_source.go new file mode 100644 index 000000000000..10452affcc5f --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/store_data_source.go @@ -0,0 +1,55 @@ +// 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/internal/client" +) + +var _ datasource.DataSource = &StoreDataSource{} + +func NewStoreDataSource() datasource.DataSource { + return &StoreDataSource{} +} + +type StoreDataSource struct { + client *client.Client +} + +func (d *StoreDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_store" +} + +func (d *StoreDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Fetches a store data source.", + Attributes: map[string]schema.Attribute{ + }, + } +} + +func (d *StoreDataSource) 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 *StoreDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + resp.Diagnostics.AddError("Not Supported", "Read is not supported for store") +} diff --git a/samples/client/petstore/terraform/internal/provider/store_model.go b/samples/client/petstore/terraform/internal/provider/store_model.go new file mode 100644 index 000000000000..40435f32d9e9 --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/store_model.go @@ -0,0 +1,8 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. +package provider + + +// StoreModel is the Terraform model for store. +type StoreModel struct { +} + diff --git a/samples/client/petstore/terraform/internal/provider/store_resource.go b/samples/client/petstore/terraform/internal/provider/store_resource.go new file mode 100644 index 000000000000..8a12609e4c19 --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/store_resource.go @@ -0,0 +1,77 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. +package provider + +import ( + "context" + "fmt" + + + + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + + + + "github.com/example/terraform-provider-petstore/internal/client" +) + +var _ resource.Resource = &StoreResource{} +var _ resource.ResourceWithImportState = &StoreResource{} + +func NewStoreResource() resource.Resource { + return &StoreResource{} +} + +type StoreResource struct { + client *client.Client +} + +func (r *StoreResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_store" +} + +func (r *StoreResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages a store resource.", + Attributes: map[string]schema.Attribute{ + }, + } +} + +func (r *StoreResource) 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 *StoreResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Not Supported", "Create is not supported for store") +} + +func (r *StoreResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + resp.Diagnostics.AddError("Not Supported", "Read is not supported for store") +} + +func (r *StoreResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Not Supported", "Update is not supported for store") +} + +func (r *StoreResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Not Supported", "Delete is not supported for store") +} + +func (r *StoreResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/samples/client/petstore/terraform/internal/provider/user_data_source.go b/samples/client/petstore/terraform/internal/provider/user_data_source.go new file mode 100644 index 000000000000..5946345c17eb --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/user_data_source.go @@ -0,0 +1,111 @@ +// 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/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-log/tflog" + + "github.com/example/terraform-provider-petstore/internal/client" +) + +var _ datasource.DataSource = &UserDataSource{} + +func NewUserDataSource() datasource.DataSource { + return &UserDataSource{} +} + +type UserDataSource struct { + client *client.Client +} + +func (d *UserDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_user" +} + +func (d *UserDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Fetches a user data source.", + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + Description: "", + }, + "username": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "first_name": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "last_name": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "email": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "password": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "phone": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "user_status": schema.Int64Attribute{ + Computed: true, + Description: "User Status", + }, + }, + } +} + +func (d *UserDataSource) 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 *UserDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config UserModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + respBody, err := d.client.DoRequest(ctx, "GET", fmt.Sprintf("/user/%v", config.Username.ValueString()), nil) + if err != nil { + resp.Diagnostics.AddError("Error reading user", err.Error()) + return + } + + var result client.User + if err := json.Unmarshal(respBody, &result); err != nil { + resp.Diagnostics.AddError("Error parsing response", err.Error()) + return + } + + config.FromClientModel(&result) + + tflog.Trace(ctx, "read user data source") + resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) +} diff --git a/samples/client/petstore/terraform/internal/provider/user_model.go b/samples/client/petstore/terraform/internal/provider/user_model.go new file mode 100644 index 000000000000..62587f6b8ddf --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/user_model.go @@ -0,0 +1,62 @@ +// 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/internal/client" +) + +// UserModel is the Terraform model for user. +type UserModel struct { + Id types.Int64 `tfsdk:"id"` + Username types.String `tfsdk:"username"` + FirstName types.String `tfsdk:"first_name"` + LastName types.String `tfsdk:"last_name"` + Email types.String `tfsdk:"email"` + Password types.String `tfsdk:"password"` + Phone types.String `tfsdk:"phone"` + UserStatus types.Int64 `tfsdk:"user_status"` +} + +// ToClientModel converts a Terraform model to a client model. +func (m *UserModel) ToClientModel() *client.User { + out := &client.User{} + if !m.Id.IsNull() && !m.Id.IsUnknown() { + out.Id = int64(m.Id.ValueInt64()) + } + if !m.Username.IsNull() && !m.Username.IsUnknown() { + out.Username = m.Username.ValueString() + } + if !m.FirstName.IsNull() && !m.FirstName.IsUnknown() { + out.FirstName = m.FirstName.ValueString() + } + if !m.LastName.IsNull() && !m.LastName.IsUnknown() { + out.LastName = m.LastName.ValueString() + } + if !m.Email.IsNull() && !m.Email.IsUnknown() { + out.Email = m.Email.ValueString() + } + if !m.Password.IsNull() && !m.Password.IsUnknown() { + out.Password = m.Password.ValueString() + } + if !m.Phone.IsNull() && !m.Phone.IsUnknown() { + out.Phone = m.Phone.ValueString() + } + if !m.UserStatus.IsNull() && !m.UserStatus.IsUnknown() { + out.UserStatus = int32(m.UserStatus.ValueInt64()) + } + return out +} + +// FromClientModel updates the Terraform model from a client model. +func (m *UserModel) FromClientModel(c *client.User) { + m.Id = types.Int64Value(int64(c.Id)) + m.Username = types.StringValue(c.Username) + m.FirstName = types.StringValue(c.FirstName) + m.LastName = types.StringValue(c.LastName) + m.Email = types.StringValue(c.Email) + m.Password = types.StringValue(c.Password) + m.Phone = types.StringValue(c.Phone) + m.UserStatus = types.Int64Value(int64(c.UserStatus)) +} diff --git a/samples/client/petstore/terraform/internal/provider/user_resource.go b/samples/client/petstore/terraform/internal/provider/user_resource.go new file mode 100644 index 000000000000..dc8102202c44 --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/user_resource.go @@ -0,0 +1,193 @@ +// 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-log/tflog" + + + + "github.com/example/terraform-provider-petstore/internal/client" +) + +var _ resource.Resource = &UserResource{} +var _ resource.ResourceWithImportState = &UserResource{} + +func NewUserResource() resource.Resource { + return &UserResource{} +} + +type UserResource struct { + client *client.Client +} + +func (r *UserResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_user" +} + +func (r *UserResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages a user resource.", + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Optional: true, + Description: "", + }, + "username": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "first_name": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "last_name": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "email": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "password": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "phone": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "user_status": schema.Int64Attribute{ + Optional: true, + Description: "User Status", + }, + }, + } +} + +func (r *UserResource) 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 *UserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan UserModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + reqBody := plan.ToClientModel() + + respBody, err := r.client.DoRequest(ctx, "POST", "/user", reqBody) + if err != nil { + resp.Diagnostics.AddError("Error creating user", err.Error()) + return + } + + var result client.User + if err := json.Unmarshal(respBody, &result); err != nil { + resp.Diagnostics.AddError("Error parsing response", err.Error()) + return + } + + plan.FromClientModel(&result) + + tflog.Trace(ctx, "created user resource") + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *UserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state UserModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + respBody, err := r.client.DoRequest(ctx, "GET", fmt.Sprintf("/user/%v", state.Username.ValueString()), nil) + if err != nil { + resp.Diagnostics.AddError("Error reading user", err.Error()) + return + } + + var result client.User + 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)...) +} + +func (r *UserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan UserModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + reqBody := plan.ToClientModel() + + respBody, err := r.client.DoRequest(ctx, "PUT", fmt.Sprintf("/user/%v", plan.Username.ValueString()), reqBody) + if err != nil { + resp.Diagnostics.AddError("Error updating user", err.Error()) + return + } + + var result client.User + if err := json.Unmarshal(respBody, &result); err != nil { + resp.Diagnostics.AddError("Error parsing response", err.Error()) + return + } + + plan.FromClientModel(&result) + + tflog.Trace(ctx, "updated user resource") + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *UserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state UserModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.DoRequest(ctx, "DELETE", fmt.Sprintf("/user/%v", state.Username.ValueString()), nil) + if err != nil { + resp.Diagnostics.AddError("Error deleting user", err.Error()) + return + } + + tflog.Trace(ctx, "deleted user resource") +} + +func (r *UserResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("username"), req, resp) +} diff --git a/samples/client/petstore/terraform/internal/provider/user_resource_test.go b/samples/client/petstore/terraform/internal/provider/user_resource_test.go new file mode 100644 index 000000000000..644853dcdf36 --- /dev/null +++ b/samples/client/petstore/terraform/internal/provider/user_resource_test.go @@ -0,0 +1,93 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccUserResource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: testAccUserResourceConfig("johndoe", "John", "Doe", "john@example.com"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("petstore_user.test", "username", "johndoe"), + resource.TestCheckResourceAttr("petstore_user.test", "first_name", "John"), + resource.TestCheckResourceAttr("petstore_user.test", "last_name", "Doe"), + resource.TestCheckResourceAttr("petstore_user.test", "email", "john@example.com"), + ), + }, + // ImportState testing + { + ResourceName: "petstore_user.test", + ImportState: true, + ImportStateVerify: true, + // password is sensitive and may not be returned on read + ImportStateVerifyIgnore: []string{"password"}, + }, + // Update testing + { + Config: testAccUserResourceConfig("johndoe", "Jane", "Doe", "jane@example.com"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("petstore_user.test", "username", "johndoe"), + resource.TestCheckResourceAttr("petstore_user.test", "first_name", "Jane"), + resource.TestCheckResourceAttr("petstore_user.test", "email", "jane@example.com"), + ), + }, + // Delete testing is automatically handled by TestCase + }, + }) +} + +func TestAccUserResource_allFields(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccUserResourceAllFieldsConfig(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("petstore_user.test", "username", "testuser"), + resource.TestCheckResourceAttr("petstore_user.test", "first_name", "Test"), + resource.TestCheckResourceAttr("petstore_user.test", "last_name", "User"), + resource.TestCheckResourceAttr("petstore_user.test", "email", "test@example.com"), + resource.TestCheckResourceAttr("petstore_user.test", "phone", "555-1234"), + resource.TestCheckResourceAttr("petstore_user.test", "user_status", "1"), + ), + }, + }, + }) +} + +func testAccUserResourceConfig(username, firstName, lastName, email string) string { + return fmt.Sprintf(` +%s + +resource "petstore_user" "test" { + username = %[2]q + first_name = %[3]q + last_name = %[4]q + email = %[5]q + password = "secret123" +} +`, testAccProviderConfig, username, firstName, lastName, email) +} + +func testAccUserResourceAllFieldsConfig() string { + return fmt.Sprintf(` +%s + +resource "petstore_user" "test" { + username = "testuser" + first_name = "Test" + last_name = "User" + email = "test@example.com" + password = "secret123" + phone = "555-1234" + user_status = 1 +} +`, testAccProviderConfig) +} diff --git a/samples/client/petstore/terraform/main.go b/samples/client/petstore/terraform/main.go new file mode 100644 index 000000000000..f783fef81479 --- /dev/null +++ b/samples/client/petstore/terraform/main.go @@ -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/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", + Debug: debug, + } + + err := providerserver.Serve(context.Background(), provider.New(version), opts) + + if err != nil { + log.Fatal(err.Error()) + } +} From c5a0e8155dfb126784c52dddfabff7228984b206 Mon Sep 17 00:00:00 2001 From: Jason D'Amour Date: Thu, 12 Feb 2026 05:45:25 +0000 Subject: [PATCH 3/7] chore: docs --- docs/generators/terraform-provider.md | 229 +++++++++++++++++++++++ samples/client/petstore/terraform/go.mod | 55 +----- 2 files changed, 230 insertions(+), 54 deletions(-) create mode 100644 docs/generators/terraform-provider.md diff --git a/docs/generators/terraform-provider.md b/docs/generators/terraform-provider.md new file mode 100644 index 000000000000..8f14dff0c1c9 --- /dev/null +++ b/docs/generators/terraform-provider.md @@ -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 + +
    +
  • bool
  • +
  • byte
  • +
  • complex128
  • +
  • complex64
  • +
  • float32
  • +
  • float64
  • +
  • int
  • +
  • int32
  • +
  • int64
  • +
  • interface{}
  • +
  • map[string]interface{}
  • +
  • rune
  • +
  • string
  • +
  • uint
  • +
  • uint32
  • +
  • uint64
  • +
+ +## RESERVED WORDS + +
    +
  • bool
  • +
  • break
  • +
  • byte
  • +
  • case
  • +
  • chan
  • +
  • complex128
  • +
  • complex64
  • +
  • const
  • +
  • continue
  • +
  • default
  • +
  • defer
  • +
  • else
  • +
  • error
  • +
  • fallthrough
  • +
  • float32
  • +
  • float64
  • +
  • for
  • +
  • func
  • +
  • go
  • +
  • goto
  • +
  • if
  • +
  • import
  • +
  • int
  • +
  • int16
  • +
  • int32
  • +
  • int64
  • +
  • int8
  • +
  • interface
  • +
  • map
  • +
  • nil
  • +
  • package
  • +
  • range
  • +
  • return
  • +
  • rune
  • +
  • select
  • +
  • string
  • +
  • struct
  • +
  • switch
  • +
  • type
  • +
  • uint
  • +
  • uint16
  • +
  • uint32
  • +
  • uint64
  • +
  • uint8
  • +
  • uintptr
  • +
  • var
  • +
+ +## 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 diff --git a/samples/client/petstore/terraform/go.mod b/samples/client/petstore/terraform/go.mod index 570887906ac9..1e0e9158140f 100644 --- a/samples/client/petstore/terraform/go.mod +++ b/samples/client/petstore/terraform/go.mod @@ -1,64 +1,11 @@ module github.com/example/terraform-provider-petstore -go 1.24.0 +go 1.22 toolchain go1.24.4 require ( github.com/hashicorp/terraform-plugin-framework v1.17.0 - github.com/hashicorp/terraform-plugin-go v0.29.0 github.com/hashicorp/terraform-plugin-log v0.10.0 github.com/hashicorp/terraform-plugin-testing v1.14.0 ) - -require ( - github.com/ProtonMail/go-crypto v1.1.6 // indirect - github.com/agext/levenshtein v1.2.2 // indirect - github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect - github.com/cloudflare/circl v1.6.1 // indirect - github.com/fatih/color v1.16.0 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/go-cmp v0.7.0 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect - github.com/hashicorp/go-checkpoint v0.5.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-cty v1.5.0 // indirect - github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.7.0 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect - github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect - github.com/hashicorp/hc-install v0.9.2 // indirect - github.com/hashicorp/hcl/v2 v2.24.0 // indirect - github.com/hashicorp/logutils v1.0.0 // indirect - github.com/hashicorp/terraform-exec v0.24.0 // indirect - github.com/hashicorp/terraform-json v0.27.2 // indirect - github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 // indirect - github.com/hashicorp/terraform-registry-address v0.4.0 // indirect - github.com/hashicorp/terraform-svchost v0.1.1 // indirect - github.com/hashicorp/yamux v0.1.2 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-testing-interface v1.14.1 // indirect - github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/oklog/run v1.1.0 // indirect - github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect - github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/zclconf/go-cty v1.17.0 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect - golang.org/x/tools v0.38.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/grpc v1.75.1 // indirect - google.golang.org/protobuf v1.36.9 // indirect -) From cfdb868614efc2409a9ac35009f6afd0ad8c8636 Mon Sep 17 00:00:00 2001 From: Jason D'Amour Date: Thu, 12 Feb 2026 06:18:30 +0000 Subject: [PATCH 4/7] terraform: add more sample tests and ci workflow --- .github/workflows/samples-terraform.yaml | 42 ++++ ...erraform-provider-allof-discriminator.yaml | 11 + ...rraform-provider-oneof-anyof-required.yaml | 11 + ...m-provider-oneof-discriminator-lookup.yaml | 11 + .../terraform-provider-petstore-addpet.yaml | 11 + .../terraform-provider-petstore-server.yaml | 11 + .../terraform/allof-discriminator/.gitignore | 12 ++ .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/FILES | 11 + .../.openapi-generator/VERSION | 1 + .../terraform/allof-discriminator/GNUmakefile | 27 +++ .../terraform/allof-discriminator/README.md | 48 +++++ .../examples/provider/provider.tf | 13 ++ .../terraform/allof-discriminator/go.mod | 11 + .../terraform/allof-discriminator/go.sum | 99 +++++++++ .../internal/client/client.go | 78 +++++++ .../internal/client/model_additional_data.go | 11 + .../internal/client/model_base/item.go | 9 + .../internal/client/model_final_item.go | 11 + .../internal/provider/provider.go | 114 ++++++++++ .../terraform/allof-discriminator/main.go | 35 +++ .../terraform/oneof-anyof-required/.gitignore | 12 ++ .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/FILES | 12 ++ .../.openapi-generator/VERSION | 1 + .../oneof-anyof-required/GNUmakefile | 27 +++ .../terraform/oneof-anyof-required/README.md | 48 +++++ .../examples/provider/provider.tf | 13 ++ .../terraform/oneof-anyof-required/go.mod | 11 + .../terraform/oneof-anyof-required/go.sum | 99 +++++++++ .../internal/client/client.go | 78 +++++++ .../internal/client/model_nested_object1.go | 8 + .../internal/client/model_nested_object2.go | 8 + .../internal/client/model_object.go | 9 + .../internal/client/model_object2.go | 9 + .../internal/provider/provider.go | 114 ++++++++++ .../terraform/oneof-anyof-required/main.go | 35 +++ .../oneof-discriminator-lookup/.gitignore | 12 ++ .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/FILES | 11 + .../.openapi-generator/VERSION | 1 + .../oneof-discriminator-lookup/GNUmakefile | 27 +++ .../oneof-discriminator-lookup/README.md | 48 +++++ .../examples/provider/provider.tf | 13 ++ .../oneof-discriminator-lookup/go.mod | 11 + .../oneof-discriminator-lookup/go.sum | 99 +++++++++ .../internal/client/client.go | 78 +++++++ .../internal/client/model_nested_object1.go | 9 + .../internal/client/model_nested_object2.go | 9 + .../internal/client/model_object.go | 9 + .../internal/provider/provider.go | 114 ++++++++++ .../oneof-discriminator-lookup/main.go | 35 +++ .../petstore/terraform-addpet/.gitignore | 12 ++ .../.openapi-generator-ignore | 23 ++ .../terraform-addpet/.openapi-generator/FILES | 14 ++ .../.openapi-generator/VERSION | 1 + .../petstore/terraform-addpet/GNUmakefile | 27 +++ .../petstore/terraform-addpet/README.md | 48 +++++ .../examples/provider/provider.tf | 13 ++ .../client/petstore/terraform-addpet/go.mod | 11 + .../client/petstore/terraform-addpet/go.sum | 99 +++++++++ .../internal/client/client.go | 78 +++++++ .../internal/client/model_category.go | 9 + .../internal/client/model_pet.go | 13 ++ .../internal/client/model_tag.go | 9 + .../internal/provider/pet_data_source.go | 79 +++++++ .../internal/provider/pet_model.go | 40 ++++ .../internal/provider/pet_resource.go | 130 +++++++++++ .../internal/provider/provider.go | 116 ++++++++++ .../client/petstore/terraform-addpet/main.go | 35 +++ .../petstore/terraform-server/.gitignore | 12 ++ .../.openapi-generator-ignore | 23 ++ .../terraform-server/.openapi-generator/FILES | 33 +++ .../.openapi-generator/VERSION | 1 + .../petstore/terraform-server/GNUmakefile | 27 +++ .../petstore/terraform-server/README.md | 48 +++++ .../examples/provider/provider.tf | 13 ++ .../client/petstore/terraform-server/go.mod | 11 + .../client/petstore/terraform-server/go.sum | 99 +++++++++ .../internal/client/client.go | 78 +++++++ .../internal/client/model_an_object.go | 9 + .../internal/client/model_api_response.go | 10 + .../internal/client/model_category.go | 9 + .../internal/client/model_colour.go | 7 + .../internal/client/model_gender.go | 7 + .../internal/client/model_order.go | 14 ++ .../internal/client/model_order_info.go | 10 + .../internal/client/model_pet.go | 13 ++ .../internal/client/model_special_info.go | 9 + .../internal/client/model_species.go | 7 + .../internal/client/model_tag.go | 9 + .../internal/client/model_user.go | 17 ++ .../internal/client/model_user_nullable.go | 17 ++ .../internal/provider/fake_data_source.go | 55 +++++ .../internal/provider/fake_model.go | 8 + .../internal/provider/fake_resource.go | 77 +++++++ .../internal/provider/pet_data_source.go | 103 +++++++++ .../internal/provider/pet_model.go | 40 ++++ .../internal/provider/pet_resource.go | 164 ++++++++++++++ .../internal/provider/provider.go | 122 +++++++++++ .../internal/provider/store_data_source.go | 55 +++++ .../internal/provider/store_model.go | 8 + .../internal/provider/store_resource.go | 77 +++++++ .../internal/provider/user_data_source.go | 119 ++++++++++ .../internal/provider/user_model.go | 64 ++++++ .../internal/provider/user_resource.go | 204 ++++++++++++++++++ .../client/petstore/terraform-server/main.go | 35 +++ 107 files changed, 3977 insertions(+) create mode 100644 .github/workflows/samples-terraform.yaml create mode 100644 bin/configs/terraform-provider-allof-discriminator.yaml create mode 100644 bin/configs/terraform-provider-oneof-anyof-required.yaml create mode 100644 bin/configs/terraform-provider-oneof-discriminator-lookup.yaml create mode 100644 bin/configs/terraform-provider-petstore-addpet.yaml create mode 100644 bin/configs/terraform-provider-petstore-server.yaml create mode 100644 samples/client/others/terraform/allof-discriminator/.gitignore create mode 100644 samples/client/others/terraform/allof-discriminator/.openapi-generator-ignore create mode 100644 samples/client/others/terraform/allof-discriminator/.openapi-generator/FILES create mode 100644 samples/client/others/terraform/allof-discriminator/.openapi-generator/VERSION create mode 100644 samples/client/others/terraform/allof-discriminator/GNUmakefile create mode 100644 samples/client/others/terraform/allof-discriminator/README.md create mode 100644 samples/client/others/terraform/allof-discriminator/examples/provider/provider.tf create mode 100644 samples/client/others/terraform/allof-discriminator/go.mod create mode 100644 samples/client/others/terraform/allof-discriminator/go.sum create mode 100644 samples/client/others/terraform/allof-discriminator/internal/client/client.go create mode 100644 samples/client/others/terraform/allof-discriminator/internal/client/model_additional_data.go create mode 100644 samples/client/others/terraform/allof-discriminator/internal/client/model_base/item.go create mode 100644 samples/client/others/terraform/allof-discriminator/internal/client/model_final_item.go create mode 100644 samples/client/others/terraform/allof-discriminator/internal/provider/provider.go create mode 100644 samples/client/others/terraform/allof-discriminator/main.go create mode 100644 samples/client/others/terraform/oneof-anyof-required/.gitignore create mode 100644 samples/client/others/terraform/oneof-anyof-required/.openapi-generator-ignore create mode 100644 samples/client/others/terraform/oneof-anyof-required/.openapi-generator/FILES create mode 100644 samples/client/others/terraform/oneof-anyof-required/.openapi-generator/VERSION create mode 100644 samples/client/others/terraform/oneof-anyof-required/GNUmakefile create mode 100644 samples/client/others/terraform/oneof-anyof-required/README.md create mode 100644 samples/client/others/terraform/oneof-anyof-required/examples/provider/provider.tf create mode 100644 samples/client/others/terraform/oneof-anyof-required/go.mod create mode 100644 samples/client/others/terraform/oneof-anyof-required/go.sum create mode 100644 samples/client/others/terraform/oneof-anyof-required/internal/client/client.go create mode 100644 samples/client/others/terraform/oneof-anyof-required/internal/client/model_nested_object1.go create mode 100644 samples/client/others/terraform/oneof-anyof-required/internal/client/model_nested_object2.go create mode 100644 samples/client/others/terraform/oneof-anyof-required/internal/client/model_object.go create mode 100644 samples/client/others/terraform/oneof-anyof-required/internal/client/model_object2.go create mode 100644 samples/client/others/terraform/oneof-anyof-required/internal/provider/provider.go create mode 100644 samples/client/others/terraform/oneof-anyof-required/main.go create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/.gitignore create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator-ignore create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator/FILES create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator/VERSION create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/GNUmakefile create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/README.md create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/examples/provider/provider.tf create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/go.mod create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/go.sum create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/internal/client/client.go create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_nested_object1.go create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_nested_object2.go create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_object.go create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/internal/provider/provider.go create mode 100644 samples/client/others/terraform/oneof-discriminator-lookup/main.go create mode 100644 samples/client/petstore/terraform-addpet/.gitignore create mode 100644 samples/client/petstore/terraform-addpet/.openapi-generator-ignore create mode 100644 samples/client/petstore/terraform-addpet/.openapi-generator/FILES create mode 100644 samples/client/petstore/terraform-addpet/.openapi-generator/VERSION create mode 100644 samples/client/petstore/terraform-addpet/GNUmakefile create mode 100644 samples/client/petstore/terraform-addpet/README.md create mode 100644 samples/client/petstore/terraform-addpet/examples/provider/provider.tf create mode 100644 samples/client/petstore/terraform-addpet/go.mod create mode 100644 samples/client/petstore/terraform-addpet/go.sum create mode 100644 samples/client/petstore/terraform-addpet/internal/client/client.go create mode 100644 samples/client/petstore/terraform-addpet/internal/client/model_category.go create mode 100644 samples/client/petstore/terraform-addpet/internal/client/model_pet.go create mode 100644 samples/client/petstore/terraform-addpet/internal/client/model_tag.go create mode 100644 samples/client/petstore/terraform-addpet/internal/provider/pet_data_source.go create mode 100644 samples/client/petstore/terraform-addpet/internal/provider/pet_model.go create mode 100644 samples/client/petstore/terraform-addpet/internal/provider/pet_resource.go create mode 100644 samples/client/petstore/terraform-addpet/internal/provider/provider.go create mode 100644 samples/client/petstore/terraform-addpet/main.go create mode 100644 samples/client/petstore/terraform-server/.gitignore create mode 100644 samples/client/petstore/terraform-server/.openapi-generator-ignore create mode 100644 samples/client/petstore/terraform-server/.openapi-generator/FILES create mode 100644 samples/client/petstore/terraform-server/.openapi-generator/VERSION create mode 100644 samples/client/petstore/terraform-server/GNUmakefile create mode 100644 samples/client/petstore/terraform-server/README.md create mode 100644 samples/client/petstore/terraform-server/examples/provider/provider.tf create mode 100644 samples/client/petstore/terraform-server/go.mod create mode 100644 samples/client/petstore/terraform-server/go.sum create mode 100644 samples/client/petstore/terraform-server/internal/client/client.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_an_object.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_api_response.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_category.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_colour.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_gender.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_order.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_order_info.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_pet.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_special_info.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_species.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_tag.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_user.go create mode 100644 samples/client/petstore/terraform-server/internal/client/model_user_nullable.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/fake_data_source.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/fake_model.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/fake_resource.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/pet_data_source.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/pet_model.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/pet_resource.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/provider.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/store_data_source.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/store_model.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/store_resource.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/user_data_source.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/user_model.go create mode 100644 samples/client/petstore/terraform-server/internal/provider/user_resource.go create mode 100644 samples/client/petstore/terraform-server/main.go diff --git a/.github/workflows/samples-terraform.yaml b/.github/workflows/samples-terraform.yaml new file mode 100644 index 000000000000..4c1a04462660 --- /dev/null +++ b/.github/workflows/samples-terraform.yaml @@ -0,0 +1,42 @@ +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: Build provider + working-directory: ${{ matrix.sample }} + run: go build -v ./... + - name: Run acceptance tests + working-directory: ${{ matrix.sample }} + run: TF_ACC=1 go test ./... -v -timeout 120m diff --git a/bin/configs/terraform-provider-allof-discriminator.yaml b/bin/configs/terraform-provider-allof-discriminator.yaml new file mode 100644 index 000000000000..e1b81ffb1def --- /dev/null +++ b/bin/configs/terraform-provider-allof-discriminator.yaml @@ -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" diff --git a/bin/configs/terraform-provider-oneof-anyof-required.yaml b/bin/configs/terraform-provider-oneof-anyof-required.yaml new file mode 100644 index 000000000000..da6bf834c24b --- /dev/null +++ b/bin/configs/terraform-provider-oneof-anyof-required.yaml @@ -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" diff --git a/bin/configs/terraform-provider-oneof-discriminator-lookup.yaml b/bin/configs/terraform-provider-oneof-discriminator-lookup.yaml new file mode 100644 index 000000000000..0f2a5034dac1 --- /dev/null +++ b/bin/configs/terraform-provider-oneof-discriminator-lookup.yaml @@ -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" diff --git a/bin/configs/terraform-provider-petstore-addpet.yaml b/bin/configs/terraform-provider-petstore-addpet.yaml new file mode 100644 index 000000000000..def0ff729b72 --- /dev/null +++ b/bin/configs/terraform-provider-petstore-addpet.yaml @@ -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" diff --git a/bin/configs/terraform-provider-petstore-server.yaml b/bin/configs/terraform-provider-petstore-server.yaml new file mode 100644 index 000000000000..9d6322fefe35 --- /dev/null +++ b/bin/configs/terraform-provider-petstore-server.yaml @@ -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" diff --git a/samples/client/others/terraform/allof-discriminator/.gitignore b/samples/client/others/terraform/allof-discriminator/.gitignore new file mode 100644 index 000000000000..96bdf8b8acca --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/.gitignore @@ -0,0 +1,12 @@ +*.dll +*.exe +*.exe~ +*.dylib +*.so +*.test +*.out +*.tfstate +*.tfstate.* +.terraform/ +terraform.tfvars +terraform-provider-allof diff --git a/samples/client/others/terraform/allof-discriminator/.openapi-generator-ignore b/samples/client/others/terraform/allof-discriminator/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/.openapi-generator-ignore @@ -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 diff --git a/samples/client/others/terraform/allof-discriminator/.openapi-generator/FILES b/samples/client/others/terraform/allof-discriminator/.openapi-generator/FILES new file mode 100644 index 000000000000..637a144f29ec --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/.openapi-generator/FILES @@ -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 diff --git a/samples/client/others/terraform/allof-discriminator/.openapi-generator/VERSION b/samples/client/others/terraform/allof-discriminator/.openapi-generator/VERSION new file mode 100644 index 000000000000..193a12d6e891 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.20.0-SNAPSHOT diff --git a/samples/client/others/terraform/allof-discriminator/GNUmakefile b/samples/client/others/terraform/allof-discriminator/GNUmakefile new file mode 100644 index 000000000000..2ab48f3d4332 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/GNUmakefile @@ -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 ./... diff --git a/samples/client/others/terraform/allof-discriminator/README.md b/samples/client/others/terraform/allof-discriminator/README.md new file mode 100644 index 000000000000..3a1284d153fe --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/README.md @@ -0,0 +1,48 @@ +# 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.21 + +## 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. + +To generate or update documentation, run `go generate`. + +In order to run the full suite of Acceptance tests, run `make testacc`. + +```shell +make testacc +``` diff --git a/samples/client/others/terraform/allof-discriminator/examples/provider/provider.tf b/samples/client/others/terraform/allof-discriminator/examples/provider/provider.tf new file mode 100644 index 000000000000..a6123fa8379a --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/examples/provider/provider.tf @@ -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" +} diff --git a/samples/client/others/terraform/allof-discriminator/go.mod b/samples/client/others/terraform/allof-discriminator/go.mod new file mode 100644 index 000000000000..a71d3eda02cb --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/go.mod @@ -0,0 +1,11 @@ +module github.com/example/terraform-provider-allof + +go 1.22 + +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 +) diff --git a/samples/client/others/terraform/allof-discriminator/go.sum b/samples/client/others/terraform/allof-discriminator/go.sum new file mode 100644 index 000000000000..8888a9727e10 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/go.sum @@ -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= diff --git a/samples/client/others/terraform/allof-discriminator/internal/client/client.go b/samples/client/others/terraform/allof-discriminator/internal/client/client.go new file mode 100644 index 000000000000..247e45a1c730 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/internal/client/client.go @@ -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 +} diff --git a/samples/client/others/terraform/allof-discriminator/internal/client/model_additional_data.go b/samples/client/others/terraform/allof-discriminator/internal/client/model_additional_data.go new file mode 100644 index 000000000000..a45565ac18e6 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/internal/client/model_additional_data.go @@ -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"` +} diff --git a/samples/client/others/terraform/allof-discriminator/internal/client/model_base/item.go b/samples/client/others/terraform/allof-discriminator/internal/client/model_base/item.go new file mode 100644 index 000000000000..4d1460216564 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/internal/client/model_base/item.go @@ -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"` +} diff --git a/samples/client/others/terraform/allof-discriminator/internal/client/model_final_item.go b/samples/client/others/terraform/allof-discriminator/internal/client/model_final_item.go new file mode 100644 index 000000000000..9c6acab04a40 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/internal/client/model_final_item.go @@ -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"` +} diff --git a/samples/client/others/terraform/allof-discriminator/internal/provider/provider.go b/samples/client/others/terraform/allof-discriminator/internal/provider/provider.go new file mode 100644 index 000000000000..7061574fadef --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/internal/provider/provider.go @@ -0,0 +1,114 @@ +// 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 + } + + endpoint := config.Endpoint.ValueString() + if endpoint == "" { + endpoint = "http://localhost" + } + + 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{ + } +} diff --git a/samples/client/others/terraform/allof-discriminator/main.go b/samples/client/others/terraform/allof-discriminator/main.go new file mode 100644 index 000000000000..467e120d0615 --- /dev/null +++ b/samples/client/others/terraform/allof-discriminator/main.go @@ -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()) + } +} diff --git a/samples/client/others/terraform/oneof-anyof-required/.gitignore b/samples/client/others/terraform/oneof-anyof-required/.gitignore new file mode 100644 index 000000000000..89e30c71b4f7 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/.gitignore @@ -0,0 +1,12 @@ +*.dll +*.exe +*.exe~ +*.dylib +*.so +*.test +*.out +*.tfstate +*.tfstate.* +.terraform/ +terraform.tfvars +terraform-provider-oneof diff --git a/samples/client/others/terraform/oneof-anyof-required/.openapi-generator-ignore b/samples/client/others/terraform/oneof-anyof-required/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/.openapi-generator-ignore @@ -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 diff --git a/samples/client/others/terraform/oneof-anyof-required/.openapi-generator/FILES b/samples/client/others/terraform/oneof-anyof-required/.openapi-generator/FILES new file mode 100644 index 000000000000..2f87d316690a --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/.openapi-generator/FILES @@ -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 diff --git a/samples/client/others/terraform/oneof-anyof-required/.openapi-generator/VERSION b/samples/client/others/terraform/oneof-anyof-required/.openapi-generator/VERSION new file mode 100644 index 000000000000..193a12d6e891 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.20.0-SNAPSHOT diff --git a/samples/client/others/terraform/oneof-anyof-required/GNUmakefile b/samples/client/others/terraform/oneof-anyof-required/GNUmakefile new file mode 100644 index 000000000000..6278c63e1414 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/GNUmakefile @@ -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 ./... diff --git a/samples/client/others/terraform/oneof-anyof-required/README.md b/samples/client/others/terraform/oneof-anyof-required/README.md new file mode 100644 index 000000000000..065a876d1202 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/README.md @@ -0,0 +1,48 @@ +# 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.21 + +## 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. + +To generate or update documentation, run `go generate`. + +In order to run the full suite of Acceptance tests, run `make testacc`. + +```shell +make testacc +``` diff --git a/samples/client/others/terraform/oneof-anyof-required/examples/provider/provider.tf b/samples/client/others/terraform/oneof-anyof-required/examples/provider/provider.tf new file mode 100644 index 000000000000..65c15e68d717 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/examples/provider/provider.tf @@ -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" +} diff --git a/samples/client/others/terraform/oneof-anyof-required/go.mod b/samples/client/others/terraform/oneof-anyof-required/go.mod new file mode 100644 index 000000000000..a99cf7728b8b --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/go.mod @@ -0,0 +1,11 @@ +module github.com/example/terraform-provider-oneof-anyof + +go 1.22 + +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 +) diff --git a/samples/client/others/terraform/oneof-anyof-required/go.sum b/samples/client/others/terraform/oneof-anyof-required/go.sum new file mode 100644 index 000000000000..8888a9727e10 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/go.sum @@ -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= diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/client/client.go b/samples/client/others/terraform/oneof-anyof-required/internal/client/client.go new file mode 100644 index 000000000000..247e45a1c730 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/internal/client/client.go @@ -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 +} diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/client/model_nested_object1.go b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_nested_object1.go new file mode 100644 index 000000000000..99a802896c24 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_nested_object1.go @@ -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"` +} diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/client/model_nested_object2.go b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_nested_object2.go new file mode 100644 index 000000000000..058a68c6d903 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_nested_object2.go @@ -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"` +} diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object.go b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object.go new file mode 100644 index 000000000000..580bb876145b --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object.go @@ -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 + Field2 string +} diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object2.go b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object2.go new file mode 100644 index 000000000000..340d89024501 --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object2.go @@ -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 + Field2 string +} diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/provider/provider.go b/samples/client/others/terraform/oneof-anyof-required/internal/provider/provider.go new file mode 100644 index 000000000000..ca100357e27e --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/internal/provider/provider.go @@ -0,0 +1,114 @@ +// 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 + } + + endpoint := config.Endpoint.ValueString() + if endpoint == "" { + endpoint = "http://localhost" + } + + 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{ + } +} diff --git a/samples/client/others/terraform/oneof-anyof-required/main.go b/samples/client/others/terraform/oneof-anyof-required/main.go new file mode 100644 index 000000000000..f920bff94b3f --- /dev/null +++ b/samples/client/others/terraform/oneof-anyof-required/main.go @@ -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()) + } +} diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/.gitignore b/samples/client/others/terraform/oneof-discriminator-lookup/.gitignore new file mode 100644 index 000000000000..89e30c71b4f7 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/.gitignore @@ -0,0 +1,12 @@ +*.dll +*.exe +*.exe~ +*.dylib +*.so +*.test +*.out +*.tfstate +*.tfstate.* +.terraform/ +terraform.tfvars +terraform-provider-oneof diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator-ignore b/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator-ignore @@ -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 diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator/FILES b/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator/FILES new file mode 100644 index 000000000000..df1c0ded3413 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator/FILES @@ -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 diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator/VERSION b/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator/VERSION new file mode 100644 index 000000000000..193a12d6e891 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.20.0-SNAPSHOT diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/GNUmakefile b/samples/client/others/terraform/oneof-discriminator-lookup/GNUmakefile new file mode 100644 index 000000000000..2b4a6b95a2a2 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/GNUmakefile @@ -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 ./... diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/README.md b/samples/client/others/terraform/oneof-discriminator-lookup/README.md new file mode 100644 index 000000000000..b9c1b2747a7b --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/README.md @@ -0,0 +1,48 @@ +# 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.21 + +## 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. + +To generate or update documentation, run `go generate`. + +In order to run the full suite of Acceptance tests, run `make testacc`. + +```shell +make testacc +``` diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/examples/provider/provider.tf b/samples/client/others/terraform/oneof-discriminator-lookup/examples/provider/provider.tf new file mode 100644 index 000000000000..2960b9988580 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/examples/provider/provider.tf @@ -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" +} diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/go.mod b/samples/client/others/terraform/oneof-discriminator-lookup/go.mod new file mode 100644 index 000000000000..50141f0a1815 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/go.mod @@ -0,0 +1,11 @@ +module github.com/example/terraform-provider-oneof-disc + +go 1.22 + +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 +) diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/go.sum b/samples/client/others/terraform/oneof-discriminator-lookup/go.sum new file mode 100644 index 000000000000..8888a9727e10 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/go.sum @@ -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= diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/client.go b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/client.go new file mode 100644 index 000000000000..247e45a1c730 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/client.go @@ -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 +} diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_nested_object1.go b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_nested_object1.go new file mode 100644 index 000000000000..dbfccaa34fd7 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_nested_object1.go @@ -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"` +} diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_nested_object2.go b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_nested_object2.go new file mode 100644 index 000000000000..dcb9e9fab3a9 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_nested_object2.go @@ -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"` +} diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_object.go b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_object.go new file mode 100644 index 000000000000..4cd5fef8f2f7 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_object.go @@ -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 + Type string +} diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/internal/provider/provider.go b/samples/client/others/terraform/oneof-discriminator-lookup/internal/provider/provider.go new file mode 100644 index 000000000000..14fad8f85799 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/internal/provider/provider.go @@ -0,0 +1,114 @@ +// 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 + } + + endpoint := config.Endpoint.ValueString() + if endpoint == "" { + endpoint = "http://localhost" + } + + 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{ + } +} diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/main.go b/samples/client/others/terraform/oneof-discriminator-lookup/main.go new file mode 100644 index 000000000000..21fb266dc5b6 --- /dev/null +++ b/samples/client/others/terraform/oneof-discriminator-lookup/main.go @@ -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()) + } +} diff --git a/samples/client/petstore/terraform-addpet/.gitignore b/samples/client/petstore/terraform-addpet/.gitignore new file mode 100644 index 000000000000..f2e3600d79b0 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/.gitignore @@ -0,0 +1,12 @@ +*.dll +*.exe +*.exe~ +*.dylib +*.so +*.test +*.out +*.tfstate +*.tfstate.* +.terraform/ +terraform.tfvars +terraform-provider-petstore diff --git a/samples/client/petstore/terraform-addpet/.openapi-generator-ignore b/samples/client/petstore/terraform-addpet/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/.openapi-generator-ignore @@ -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 diff --git a/samples/client/petstore/terraform-addpet/.openapi-generator/FILES b/samples/client/petstore/terraform-addpet/.openapi-generator/FILES new file mode 100644 index 000000000000..8d4b253aac2a --- /dev/null +++ b/samples/client/petstore/terraform-addpet/.openapi-generator/FILES @@ -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 diff --git a/samples/client/petstore/terraform-addpet/.openapi-generator/VERSION b/samples/client/petstore/terraform-addpet/.openapi-generator/VERSION new file mode 100644 index 000000000000..193a12d6e891 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.20.0-SNAPSHOT diff --git a/samples/client/petstore/terraform-addpet/GNUmakefile b/samples/client/petstore/terraform-addpet/GNUmakefile new file mode 100644 index 000000000000..399b00b0b2fe --- /dev/null +++ b/samples/client/petstore/terraform-addpet/GNUmakefile @@ -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 ./... diff --git a/samples/client/petstore/terraform-addpet/README.md b/samples/client/petstore/terraform-addpet/README.md new file mode 100644 index 000000000000..8cfdcf7faef5 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/README.md @@ -0,0 +1,48 @@ +# 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.21 + +## 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. + +To generate or update documentation, run `go generate`. + +In order to run the full suite of Acceptance tests, run `make testacc`. + +```shell +make testacc +``` diff --git a/samples/client/petstore/terraform-addpet/examples/provider/provider.tf b/samples/client/petstore/terraform-addpet/examples/provider/provider.tf new file mode 100644 index 000000000000..bc1cbb6028ad --- /dev/null +++ b/samples/client/petstore/terraform-addpet/examples/provider/provider.tf @@ -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" +} diff --git a/samples/client/petstore/terraform-addpet/go.mod b/samples/client/petstore/terraform-addpet/go.mod new file mode 100644 index 000000000000..dbb53a1623b5 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/go.mod @@ -0,0 +1,11 @@ +module github.com/example/terraform-provider-petstore-addpet + +go 1.22 + +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 +) diff --git a/samples/client/petstore/terraform-addpet/go.sum b/samples/client/petstore/terraform-addpet/go.sum new file mode 100644 index 000000000000..8888a9727e10 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/go.sum @@ -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= diff --git a/samples/client/petstore/terraform-addpet/internal/client/client.go b/samples/client/petstore/terraform-addpet/internal/client/client.go new file mode 100644 index 000000000000..247e45a1c730 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/internal/client/client.go @@ -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 +} diff --git a/samples/client/petstore/terraform-addpet/internal/client/model_category.go b/samples/client/petstore/terraform-addpet/internal/client/model_category.go new file mode 100644 index 000000000000..1813ce260524 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/internal/client/model_category.go @@ -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]+$"` +} diff --git a/samples/client/petstore/terraform-addpet/internal/client/model_pet.go b/samples/client/petstore/terraform-addpet/internal/client/model_pet.go new file mode 100644 index 000000000000..96e95cec74c7 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/internal/client/model_pet.go @@ -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"` +} diff --git a/samples/client/petstore/terraform-addpet/internal/client/model_tag.go b/samples/client/petstore/terraform-addpet/internal/client/model_tag.go new file mode 100644 index 000000000000..6e81eb958ae7 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/internal/client/model_tag.go @@ -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"` +} diff --git a/samples/client/petstore/terraform-addpet/internal/provider/pet_data_source.go b/samples/client/petstore/terraform-addpet/internal/provider/pet_data_source.go new file mode 100644 index 000000000000..91db64b61406 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/internal/provider/pet_data_source.go @@ -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") +} diff --git a/samples/client/petstore/terraform-addpet/internal/provider/pet_model.go b/samples/client/petstore/terraform-addpet/internal/provider/pet_model.go new file mode 100644 index 000000000000..7c63ef759e59 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/internal/provider/pet_model.go @@ -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) +} diff --git a/samples/client/petstore/terraform-addpet/internal/provider/pet_resource.go b/samples/client/petstore/terraform-addpet/internal/provider/pet_resource.go new file mode 100644 index 000000000000..d7e4df7a6380 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/internal/provider/pet_resource.go @@ -0,0 +1,130 @@ +// 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) { + resp.Diagnostics.AddError("Not Supported", "Read is not supported for pet") +} + +func (r *PetResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Not Supported", "Update is not supported for pet") +} + +func (r *PetResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Not Supported", "Delete is not supported for pet") +} + +func (r *PetResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/samples/client/petstore/terraform-addpet/internal/provider/provider.go b/samples/client/petstore/terraform-addpet/internal/provider/provider.go new file mode 100644 index 000000000000..8530d80ebfee --- /dev/null +++ b/samples/client/petstore/terraform-addpet/internal/provider/provider.go @@ -0,0 +1,116 @@ +// 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 + } + + endpoint := config.Endpoint.ValueString() + if endpoint == "" { + endpoint = "http://petstore.swagger.io/v2" + } + + 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, + } +} diff --git a/samples/client/petstore/terraform-addpet/main.go b/samples/client/petstore/terraform-addpet/main.go new file mode 100644 index 000000000000..fe5e836d4041 --- /dev/null +++ b/samples/client/petstore/terraform-addpet/main.go @@ -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()) + } +} diff --git a/samples/client/petstore/terraform-server/.gitignore b/samples/client/petstore/terraform-server/.gitignore new file mode 100644 index 000000000000..f2e3600d79b0 --- /dev/null +++ b/samples/client/petstore/terraform-server/.gitignore @@ -0,0 +1,12 @@ +*.dll +*.exe +*.exe~ +*.dylib +*.so +*.test +*.out +*.tfstate +*.tfstate.* +.terraform/ +terraform.tfvars +terraform-provider-petstore diff --git a/samples/client/petstore/terraform-server/.openapi-generator-ignore b/samples/client/petstore/terraform-server/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/client/petstore/terraform-server/.openapi-generator-ignore @@ -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 diff --git a/samples/client/petstore/terraform-server/.openapi-generator/FILES b/samples/client/petstore/terraform-server/.openapi-generator/FILES new file mode 100644 index 000000000000..c087d63e2ade --- /dev/null +++ b/samples/client/petstore/terraform-server/.openapi-generator/FILES @@ -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 diff --git a/samples/client/petstore/terraform-server/.openapi-generator/VERSION b/samples/client/petstore/terraform-server/.openapi-generator/VERSION new file mode 100644 index 000000000000..193a12d6e891 --- /dev/null +++ b/samples/client/petstore/terraform-server/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.20.0-SNAPSHOT diff --git a/samples/client/petstore/terraform-server/GNUmakefile b/samples/client/petstore/terraform-server/GNUmakefile new file mode 100644 index 000000000000..322ade6623e2 --- /dev/null +++ b/samples/client/petstore/terraform-server/GNUmakefile @@ -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 ./... diff --git a/samples/client/petstore/terraform-server/README.md b/samples/client/petstore/terraform-server/README.md new file mode 100644 index 000000000000..fab107f97e4c --- /dev/null +++ b/samples/client/petstore/terraform-server/README.md @@ -0,0 +1,48 @@ +# 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.21 + +## 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. + +To generate or update documentation, run `go generate`. + +In order to run the full suite of Acceptance tests, run `make testacc`. + +```shell +make testacc +``` diff --git a/samples/client/petstore/terraform-server/examples/provider/provider.tf b/samples/client/petstore/terraform-server/examples/provider/provider.tf new file mode 100644 index 000000000000..4392153e6617 --- /dev/null +++ b/samples/client/petstore/terraform-server/examples/provider/provider.tf @@ -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" +} diff --git a/samples/client/petstore/terraform-server/go.mod b/samples/client/petstore/terraform-server/go.mod new file mode 100644 index 000000000000..1817f7399fc1 --- /dev/null +++ b/samples/client/petstore/terraform-server/go.mod @@ -0,0 +1,11 @@ +module github.com/example/terraform-provider-petstore-server + +go 1.22 + +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 +) diff --git a/samples/client/petstore/terraform-server/go.sum b/samples/client/petstore/terraform-server/go.sum new file mode 100644 index 000000000000..8888a9727e10 --- /dev/null +++ b/samples/client/petstore/terraform-server/go.sum @@ -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= diff --git a/samples/client/petstore/terraform-server/internal/client/client.go b/samples/client/petstore/terraform-server/internal/client/client.go new file mode 100644 index 000000000000..247e45a1c730 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/client.go @@ -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 +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_an_object.go b/samples/client/petstore/terraform-server/internal/client/model_an_object.go new file mode 100644 index 000000000000..96b9497536f4 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_an_object.go @@ -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"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_api_response.go b/samples/client/petstore/terraform-server/internal/client/model_api_response.go new file mode 100644 index 000000000000..8512ff6a6f5c --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_api_response.go @@ -0,0 +1,10 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// ApiResponse - Describes the result of uploading an image resource +type ApiResponse struct { + Code int32 `json:"code,omitempty"` + Type string `json:"type,omitempty"` + Message string `json:"message,omitempty"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_category.go b/samples/client/petstore/terraform-server/internal/client/model_category.go new file mode 100644 index 000000000000..1813ce260524 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_category.go @@ -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]+$"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_colour.go b/samples/client/petstore/terraform-server/internal/client/model_colour.go new file mode 100644 index 000000000000..7a6d050fb7f3 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_colour.go @@ -0,0 +1,7 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// Colour - Colour struct +type Colour struct { +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_gender.go b/samples/client/petstore/terraform-server/internal/client/model_gender.go new file mode 100644 index 000000000000..03f368de9425 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_gender.go @@ -0,0 +1,7 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// Gender - Gender struct +type Gender struct { +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_order.go b/samples/client/petstore/terraform-server/internal/client/model_order.go new file mode 100644 index 000000000000..c22eaa085bbd --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_order.go @@ -0,0 +1,14 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// Order - Order struct +type Order struct { + PetId int64 `json:"petId,omitempty"` + Quantity int32 `json:"quantity,omitempty"` + ShipDate string `json:"shipDate,omitempty"` + Id int64 `json:"id,omitempty"` + Status string `json:"status,omitempty"` + Complete bool `json:"complete,omitempty"` + Comment string `json:"comment"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_order_info.go b/samples/client/petstore/terraform-server/internal/client/model_order_info.go new file mode 100644 index 000000000000..143a569a623e --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_order_info.go @@ -0,0 +1,10 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// OrderInfo - An order info for a pets from the pet store +type OrderInfo struct { + PetId int64 `json:"petId,omitempty"` + Quantity int32 `json:"quantity,omitempty"` + ShipDate string `json:"shipDate,omitempty"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_pet.go b/samples/client/petstore/terraform-server/internal/client/model_pet.go new file mode 100644 index 000000000000..96e95cec74c7 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_pet.go @@ -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"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_special_info.go b/samples/client/petstore/terraform-server/internal/client/model_special_info.go new file mode 100644 index 000000000000..a1f3cb62bef3 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_special_info.go @@ -0,0 +1,9 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// SpecialInfo - An order info for a pets from the pet store +type SpecialInfo struct { + Promotion bool `json:"promotion,omitempty"` + Type string `json:"type,omitempty"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_species.go b/samples/client/petstore/terraform-server/internal/client/model_species.go new file mode 100644 index 000000000000..eab306cbe57d --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_species.go @@ -0,0 +1,7 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// Species - Species struct +type Species struct { +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_tag.go b/samples/client/petstore/terraform-server/internal/client/model_tag.go new file mode 100644 index 000000000000..6e81eb958ae7 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_tag.go @@ -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"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_user.go b/samples/client/petstore/terraform-server/internal/client/model_user.go new file mode 100644 index 000000000000..431bd78fb915 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_user.go @@ -0,0 +1,17 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// User - A User who is purchasing from the pet store +type User struct { + Id int64 `json:"id,omitempty"` + Username string `json:"username,omitempty"` + FirstName string `json:"firstName,omitempty"` + LastName string `json:"lastName,omitempty"` + Email string `json:"email,omitempty"` + Password string `json:"password,omitempty"` + Phone string `json:"phone,omitempty"` + UserStatus int32 `json:"userStatus,omitempty"` + DeepSliceModel [][][]Tag `json:"deepSliceModel"` + DeepSliceMap [][]AnObject `json:"deepSliceMap,omitempty"` +} diff --git a/samples/client/petstore/terraform-server/internal/client/model_user_nullable.go b/samples/client/petstore/terraform-server/internal/client/model_user_nullable.go new file mode 100644 index 000000000000..2297a6b3016c --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/client/model_user_nullable.go @@ -0,0 +1,17 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +// UserNullable - A User who is purchasing from the pet store +type UserNullable struct { + Id int64 `json:"id,omitempty"` + Username string `json:"username,omitempty"` + FirstName string `json:"firstName,omitempty"` + LastName string `json:"lastName,omitempty"` + Email string `json:"email,omitempty"` + Password string `json:"password,omitempty"` + Phone string `json:"phone,omitempty"` + UserStatus int32 `json:"userStatus,omitempty"` + DeepSliceModel [][][]Tag `json:"deepSliceModel"` + DeepSliceMap [][]AnObject `json:"deepSliceMap,omitempty"` +} diff --git a/samples/client/petstore/terraform-server/internal/provider/fake_data_source.go b/samples/client/petstore/terraform-server/internal/provider/fake_data_source.go new file mode 100644 index 000000000000..c08c8317f8d8 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/fake_data_source.go @@ -0,0 +1,55 @@ +// 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-server/internal/client" +) + +var _ datasource.DataSource = &FakeDataSource{} + +func NewFakeDataSource() datasource.DataSource { + return &FakeDataSource{} +} + +type FakeDataSource struct { + client *client.Client +} + +func (d *FakeDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_fake" +} + +func (d *FakeDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Fetches a fake data source.", + Attributes: map[string]schema.Attribute{ + }, + } +} + +func (d *FakeDataSource) 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 *FakeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + resp.Diagnostics.AddError("Not Supported", "Read is not supported for fake") +} diff --git a/samples/client/petstore/terraform-server/internal/provider/fake_model.go b/samples/client/petstore/terraform-server/internal/provider/fake_model.go new file mode 100644 index 000000000000..1f70b769304a --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/fake_model.go @@ -0,0 +1,8 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. +package provider + + +// FakeModel is the Terraform model for fake. +type FakeModel struct { +} + diff --git a/samples/client/petstore/terraform-server/internal/provider/fake_resource.go b/samples/client/petstore/terraform-server/internal/provider/fake_resource.go new file mode 100644 index 000000000000..97ef0b158d58 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/fake_resource.go @@ -0,0 +1,77 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. +package provider + +import ( + "context" + "fmt" + + + + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + + + + "github.com/example/terraform-provider-petstore-server/internal/client" +) + +var _ resource.Resource = &FakeResource{} +var _ resource.ResourceWithImportState = &FakeResource{} + +func NewFakeResource() resource.Resource { + return &FakeResource{} +} + +type FakeResource struct { + client *client.Client +} + +func (r *FakeResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_fake" +} + +func (r *FakeResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages a fake resource.", + Attributes: map[string]schema.Attribute{ + }, + } +} + +func (r *FakeResource) 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 *FakeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Not Supported", "Create is not supported for fake") +} + +func (r *FakeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + resp.Diagnostics.AddError("Not Supported", "Read is not supported for fake") +} + +func (r *FakeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Not Supported", "Update is not supported for fake") +} + +func (r *FakeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Not Supported", "Delete is not supported for fake") +} + +func (r *FakeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/samples/client/petstore/terraform-server/internal/provider/pet_data_source.go b/samples/client/petstore/terraform-server/internal/provider/pet_data_source.go new file mode 100644 index 000000000000..17be3904991b --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/pet_data_source.go @@ -0,0 +1,103 @@ +// 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/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-log/tflog" + + "github.com/example/terraform-provider-petstore-server/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) { + var config PetModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + respBody, err := d.client.DoRequest(ctx, "GET", fmt.Sprintf("/pet/%v", config.Id.ValueInt64()), nil) + if err != nil { + resp.Diagnostics.AddError("Error reading 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 + } + + config.FromClientModel(&result) + + tflog.Trace(ctx, "read pet data source") + resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) +} diff --git a/samples/client/petstore/terraform-server/internal/provider/pet_model.go b/samples/client/petstore/terraform-server/internal/provider/pet_model.go new file mode 100644 index 000000000000..e9b082143fbb --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/pet_model.go @@ -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-server/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) +} diff --git a/samples/client/petstore/terraform-server/internal/provider/pet_resource.go b/samples/client/petstore/terraform-server/internal/provider/pet_resource.go new file mode 100644 index 000000000000..f8ded489e27c --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/pet_resource.go @@ -0,0 +1,164 @@ +// 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-server/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) { + var state PetModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + respBody, err := r.client.DoRequest(ctx, "GET", fmt.Sprintf("/pet/%v", state.Id.ValueInt64()), nil) + if err != nil { + resp.Diagnostics.AddError("Error reading 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 + } + + state.FromClientModel(&result) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *PetResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Not Supported", "Update is not supported for pet") +} + +func (r *PetResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state PetModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.DoRequest(ctx, "DELETE", fmt.Sprintf("/pet/%v", state.Id.ValueInt64()), nil) + if err != nil { + resp.Diagnostics.AddError("Error deleting pet", err.Error()) + return + } + + tflog.Trace(ctx, "deleted pet resource") +} + +func (r *PetResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/samples/client/petstore/terraform-server/internal/provider/provider.go b/samples/client/petstore/terraform-server/internal/provider/provider.go new file mode 100644 index 000000000000..1f13b97a4cea --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/provider.go @@ -0,0 +1,122 @@ +// 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-server/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 + } + + endpoint := config.Endpoint.ValueString() + if endpoint == "" { + endpoint = "http://petstore.swagger.io/v2" + } + + 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{ + NewFakeResource, + NewPetResource, + NewStoreResource, + NewUserResource, + } +} + +func (p *petstoreProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + NewFakeDataSource, + NewPetDataSource, + NewStoreDataSource, + NewUserDataSource, + } +} diff --git a/samples/client/petstore/terraform-server/internal/provider/store_data_source.go b/samples/client/petstore/terraform-server/internal/provider/store_data_source.go new file mode 100644 index 000000000000..f22960d1a923 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/store_data_source.go @@ -0,0 +1,55 @@ +// 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-server/internal/client" +) + +var _ datasource.DataSource = &StoreDataSource{} + +func NewStoreDataSource() datasource.DataSource { + return &StoreDataSource{} +} + +type StoreDataSource struct { + client *client.Client +} + +func (d *StoreDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_store" +} + +func (d *StoreDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Fetches a store data source.", + Attributes: map[string]schema.Attribute{ + }, + } +} + +func (d *StoreDataSource) 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 *StoreDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + resp.Diagnostics.AddError("Not Supported", "Read is not supported for store") +} diff --git a/samples/client/petstore/terraform-server/internal/provider/store_model.go b/samples/client/petstore/terraform-server/internal/provider/store_model.go new file mode 100644 index 000000000000..40435f32d9e9 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/store_model.go @@ -0,0 +1,8 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. +package provider + + +// StoreModel is the Terraform model for store. +type StoreModel struct { +} + diff --git a/samples/client/petstore/terraform-server/internal/provider/store_resource.go b/samples/client/petstore/terraform-server/internal/provider/store_resource.go new file mode 100644 index 000000000000..6795a722c124 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/store_resource.go @@ -0,0 +1,77 @@ +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. +package provider + +import ( + "context" + "fmt" + + + + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + + + + "github.com/example/terraform-provider-petstore-server/internal/client" +) + +var _ resource.Resource = &StoreResource{} +var _ resource.ResourceWithImportState = &StoreResource{} + +func NewStoreResource() resource.Resource { + return &StoreResource{} +} + +type StoreResource struct { + client *client.Client +} + +func (r *StoreResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_store" +} + +func (r *StoreResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages a store resource.", + Attributes: map[string]schema.Attribute{ + }, + } +} + +func (r *StoreResource) 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 *StoreResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Not Supported", "Create is not supported for store") +} + +func (r *StoreResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + resp.Diagnostics.AddError("Not Supported", "Read is not supported for store") +} + +func (r *StoreResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Not Supported", "Update is not supported for store") +} + +func (r *StoreResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Not Supported", "Delete is not supported for store") +} + +func (r *StoreResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/samples/client/petstore/terraform-server/internal/provider/user_data_source.go b/samples/client/petstore/terraform-server/internal/provider/user_data_source.go new file mode 100644 index 000000000000..af5018d55da9 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/user_data_source.go @@ -0,0 +1,119 @@ +// 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/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-log/tflog" + + "github.com/example/terraform-provider-petstore-server/internal/client" +) + +var _ datasource.DataSource = &UserDataSource{} + +func NewUserDataSource() datasource.DataSource { + return &UserDataSource{} +} + +type UserDataSource struct { + client *client.Client +} + +func (d *UserDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_user" +} + +func (d *UserDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Fetches a user data source.", + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + Description: "", + }, + "username": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "first_name": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "last_name": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "email": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "password": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "phone": schema.StringAttribute{ + Computed: true, + Description: "", + }, + "user_status": schema.Int64Attribute{ + Computed: true, + Description: "User Status", + }, + "deep_slice_model": schema.StringAttribute{ + Required: true, + Description: "An array 1-deep.", + }, + "deep_slice_map": schema.StringAttribute{ + Computed: true, + Description: "An array 1-deep.", + }, + }, + } +} + +func (d *UserDataSource) 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 *UserDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config UserModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + respBody, err := d.client.DoRequest(ctx, "GET", fmt.Sprintf("/user/%v", config.Username.ValueString()), nil) + if err != nil { + resp.Diagnostics.AddError("Error reading user", err.Error()) + return + } + + var result client.User + if err := json.Unmarshal(respBody, &result); err != nil { + resp.Diagnostics.AddError("Error parsing response", err.Error()) + return + } + + config.FromClientModel(&result) + + tflog.Trace(ctx, "read user data source") + resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) +} diff --git a/samples/client/petstore/terraform-server/internal/provider/user_model.go b/samples/client/petstore/terraform-server/internal/provider/user_model.go new file mode 100644 index 000000000000..3ec8303758f8 --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/user_model.go @@ -0,0 +1,64 @@ +// 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-server/internal/client" +) + +// UserModel is the Terraform model for user. +type UserModel struct { + Id types.Int64 `tfsdk:"id"` + Username types.String `tfsdk:"username"` + FirstName types.String `tfsdk:"first_name"` + LastName types.String `tfsdk:"last_name"` + Email types.String `tfsdk:"email"` + Password types.String `tfsdk:"password"` + Phone types.String `tfsdk:"phone"` + UserStatus types.Int64 `tfsdk:"user_status"` + DeepSliceModel types.List `tfsdk:"deep_slice_model"` + DeepSliceMap types.List `tfsdk:"deep_slice_map"` +} + +// ToClientModel converts a Terraform model to a client model. +func (m *UserModel) ToClientModel() *client.User { + out := &client.User{} + if !m.Id.IsNull() && !m.Id.IsUnknown() { + out.Id = int64(m.Id.ValueInt64()) + } + if !m.Username.IsNull() && !m.Username.IsUnknown() { + out.Username = m.Username.ValueString() + } + if !m.FirstName.IsNull() && !m.FirstName.IsUnknown() { + out.FirstName = m.FirstName.ValueString() + } + if !m.LastName.IsNull() && !m.LastName.IsUnknown() { + out.LastName = m.LastName.ValueString() + } + if !m.Email.IsNull() && !m.Email.IsUnknown() { + out.Email = m.Email.ValueString() + } + if !m.Password.IsNull() && !m.Password.IsUnknown() { + out.Password = m.Password.ValueString() + } + if !m.Phone.IsNull() && !m.Phone.IsUnknown() { + out.Phone = m.Phone.ValueString() + } + if !m.UserStatus.IsNull() && !m.UserStatus.IsUnknown() { + out.UserStatus = int32(m.UserStatus.ValueInt64()) + } + return out +} + +// FromClientModel updates the Terraform model from a client model. +func (m *UserModel) FromClientModel(c *client.User) { + m.Id = types.Int64Value(int64(c.Id)) + m.Username = types.StringValue(c.Username) + m.FirstName = types.StringValue(c.FirstName) + m.LastName = types.StringValue(c.LastName) + m.Email = types.StringValue(c.Email) + m.Password = types.StringValue(c.Password) + m.Phone = types.StringValue(c.Phone) + m.UserStatus = types.Int64Value(int64(c.UserStatus)) +} diff --git a/samples/client/petstore/terraform-server/internal/provider/user_resource.go b/samples/client/petstore/terraform-server/internal/provider/user_resource.go new file mode 100644 index 000000000000..0b2a8340dbab --- /dev/null +++ b/samples/client/petstore/terraform-server/internal/provider/user_resource.go @@ -0,0 +1,204 @@ +// 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-server/internal/client" +) + +var _ resource.Resource = &UserResource{} +var _ resource.ResourceWithImportState = &UserResource{} + +func NewUserResource() resource.Resource { + return &UserResource{} +} + +type UserResource struct { + client *client.Client +} + +func (r *UserResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_user" +} + +func (r *UserResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages a user resource.", + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Optional: true, + Description: "", + }, + "username": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "first_name": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "last_name": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "email": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "password": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "phone": schema.StringAttribute{ + Optional: true, + Description: "", + }, + "user_status": schema.Int64Attribute{ + Optional: true, + Description: "User Status", + }, + "deep_slice_model": schema.ListAttribute{ + Required: true, + ElementType: types.StringType, + Description: "An array 1-deep.", + }, + "deep_slice_map": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + Description: "An array 1-deep.", + }, + }, + } +} + +func (r *UserResource) 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 *UserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan UserModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + reqBody := plan.ToClientModel() + + respBody, err := r.client.DoRequest(ctx, "POST", "/user", reqBody) + if err != nil { + resp.Diagnostics.AddError("Error creating user", err.Error()) + return + } + + var result client.User + if err := json.Unmarshal(respBody, &result); err != nil { + resp.Diagnostics.AddError("Error parsing response", err.Error()) + return + } + + plan.FromClientModel(&result) + + tflog.Trace(ctx, "created user resource") + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *UserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state UserModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + respBody, err := r.client.DoRequest(ctx, "GET", fmt.Sprintf("/user/%v", state.Username.ValueString()), nil) + if err != nil { + resp.Diagnostics.AddError("Error reading user", err.Error()) + return + } + + var result client.User + 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)...) +} + +func (r *UserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan UserModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + reqBody := plan.ToClientModel() + + respBody, err := r.client.DoRequest(ctx, "PUT", fmt.Sprintf("/user/%v", plan.Username.ValueString()), reqBody) + if err != nil { + resp.Diagnostics.AddError("Error updating user", err.Error()) + return + } + + var result client.User + if err := json.Unmarshal(respBody, &result); err != nil { + resp.Diagnostics.AddError("Error parsing response", err.Error()) + return + } + + plan.FromClientModel(&result) + + tflog.Trace(ctx, "updated user resource") + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *UserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state UserModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.DoRequest(ctx, "DELETE", fmt.Sprintf("/user/%v", state.Username.ValueString()), nil) + if err != nil { + resp.Diagnostics.AddError("Error deleting user", err.Error()) + return + } + + tflog.Trace(ctx, "deleted user resource") +} + +func (r *UserResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("username"), req, resp) +} diff --git a/samples/client/petstore/terraform-server/main.go b/samples/client/petstore/terraform-server/main.go new file mode 100644 index 000000000000..11ae54929bef --- /dev/null +++ b/samples/client/petstore/terraform-server/main.go @@ -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-server/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-server", + Debug: debug, + } + + err := providerserver.Serve(context.Background(), provider.New(version), opts) + + if err != nil { + log.Fatal(err.Error()) + } +} From 893e6a91356e2ccb8836564cf5be519fcca90403 Mon Sep 17 00:00:00 2001 From: Jason D'Amour Date: Thu, 12 Feb 2026 20:17:09 +0000 Subject: [PATCH 5/7] ci: get ci passing --- .github/workflows/samples-terraform.yaml | 4 ++++ .../languages/TerraformProviderCodegen.java | 15 +++++++++++++++ .../resources/terraform-provider/README.mustache | 15 ++++++++++++++- .../terraform-provider/gitignore.mustache | 3 ++- .../resources/terraform-provider/go.mod.mustache | 2 +- .../terraform-provider/provider.mustache | 13 ++++++++++--- .../terraform-provider/resource.mustache | 12 +++++++++--- 7 files changed, 55 insertions(+), 9 deletions(-) diff --git a/.github/workflows/samples-terraform.yaml b/.github/workflows/samples-terraform.yaml index 4c1a04462660..fdca4baeda7b 100644 --- a/.github/workflows/samples-terraform.yaml +++ b/.github/workflows/samples-terraform.yaml @@ -34,6 +34,10 @@ jobs: 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 ./... diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TerraformProviderCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TerraformProviderCodegen.java index ec3994842678..7cc6bcfbcf98 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TerraformProviderCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TerraformProviderCodegen.java @@ -444,6 +444,21 @@ public ModelsMap postProcessModels(ModelsMap 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); diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache index 2293329bef39..d154d5f9ffb4 100644 --- a/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache +++ b/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.21 +- [Go](https://golang.org/doc/install) >= 1.22 ## Building The Provider @@ -39,6 +39,19 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or 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`. diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/gitignore.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/gitignore.mustache index 1fd3996fcff0..91a35a99db75 100644 --- a/modules/openapi-generator/src/main/resources/terraform-provider/gitignore.mustache +++ b/modules/openapi-generator/src/main/resources/terraform-provider/gitignore.mustache @@ -8,5 +8,6 @@ *.tfstate *.tfstate.* .terraform/ -terraform.tfvars +*.tfvars +*.tfvars.json terraform-provider-{{providerName}} diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/go.mod.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/go.mod.mustache index 67e36d995851..b7a6caceda95 100644 --- a/modules/openapi-generator/src/main/resources/terraform-provider/go.mod.mustache +++ b/modules/openapi-generator/src/main/resources/terraform-provider/go.mod.mustache @@ -1,6 +1,6 @@ module {{gitHost}}/{{gitUserId}}/{{gitRepoId}} -go 1.22 +go 1.24.0 toolchain go1.24.4 diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/provider.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/provider.mustache index 3628c3d0d223..a1491908dfa6 100644 --- a/modules/openapi-generator/src/main/resources/terraform-provider/provider.mustache +++ b/modules/openapi-generator/src/main/resources/terraform-provider/provider.mustache @@ -78,9 +78,16 @@ func (p *{{providerName}}Provider) Configure(ctx context.Context, req provider.C return } - endpoint := config.Endpoint.ValueString() - if endpoint == "" { - endpoint = "{{{basePath}}}" + 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) diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/resource.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/resource.mustache index e5fd5b6b454d..d5660362a3e4 100644 --- a/modules/openapi-generator/src/main/resources/terraform-provider/resource.mustache +++ b/modules/openapi-generator/src/main/resources/terraform-provider/resource.mustache @@ -162,7 +162,7 @@ func (r *{{resourceClassName}}Resource) Read(ctx context.Context, req resource.R {{/hasRead}} {{^hasRead}} func (r *{{resourceClassName}}Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - resp.Diagnostics.AddError("Not Supported", "Read is not supported for {{resourceName}}") + // No read endpoint available; keep existing state as-is. } {{/hasRead}} @@ -202,7 +202,13 @@ func (r *{{resourceClassName}}Resource) Update(ctx context.Context, req resource {{/hasUpdate}} {{^hasUpdate}} func (r *{{resourceClassName}}Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Not Supported", "Update is not supported for {{resourceName}}") + // 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}} @@ -231,7 +237,7 @@ func (r *{{resourceClassName}}Resource) Delete(ctx context.Context, req resource {{/hasDelete}} {{^hasDelete}} func (r *{{resourceClassName}}Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Not Supported", "Delete is not supported for {{resourceName}}") + // No delete endpoint available; remove the resource from state. } {{/hasDelete}} From 78f9db45608c6566fd1c84f1cc4978115d715bb1 Mon Sep 17 00:00:00 2001 From: Jason D'Amour Date: Thu, 12 Feb 2026 21:24:51 +0000 Subject: [PATCH 6/7] ci: fixes --- .github/workflows/samples-terraform.yaml | 4 ++-- .../terraform/allof-discriminator/.gitignore | 3 ++- .../terraform/allof-discriminator/README.md | 15 ++++++++++++++- .../others/terraform/allof-discriminator/go.mod | 2 +- .../internal/provider/provider.go | 13 ++++++++++--- .../terraform/oneof-anyof-required/.gitignore | 3 ++- .../terraform/oneof-anyof-required/README.md | 15 ++++++++++++++- .../others/terraform/oneof-anyof-required/go.mod | 2 +- .../internal/client/model_object.go | 4 ++-- .../internal/client/model_object2.go | 4 ++-- .../internal/provider/provider.go | 13 ++++++++++--- .../oneof-discriminator-lookup/.gitignore | 3 ++- .../oneof-discriminator-lookup/README.md | 15 ++++++++++++++- .../terraform/oneof-discriminator-lookup/go.mod | 2 +- .../internal/client/model_object.go | 4 ++-- .../internal/provider/provider.go | 13 ++++++++++--- .../client/petstore/terraform-addpet/.gitignore | 3 ++- .../client/petstore/terraform-addpet/README.md | 15 ++++++++++++++- samples/client/petstore/terraform-addpet/go.mod | 2 +- .../internal/provider/pet_resource.go | 12 +++++++++--- .../internal/provider/provider.go | 13 ++++++++++--- .../client/petstore/terraform-server/.gitignore | 3 ++- .../client/petstore/terraform-server/README.md | 15 ++++++++++++++- samples/client/petstore/terraform-server/go.mod | 2 +- .../internal/provider/fake_resource.go | 12 +++++++++--- .../internal/provider/pet_resource.go | 8 +++++++- .../internal/provider/provider.go | 13 ++++++++++--- .../internal/provider/store_resource.go | 12 +++++++++--- samples/client/petstore/terraform/.gitignore | 3 ++- samples/client/petstore/terraform/README.md | 15 ++++++++++++++- samples/client/petstore/terraform/go.mod | 2 +- .../terraform/internal/provider/pet_resource.go | 8 +++++++- .../terraform/internal/provider/provider.go | 13 ++++++++++--- .../terraform/internal/provider/store_resource.go | 12 +++++++++--- 34 files changed, 220 insertions(+), 58 deletions(-) diff --git a/.github/workflows/samples-terraform.yaml b/.github/workflows/samples-terraform.yaml index fdca4baeda7b..04504f8f7c16 100644 --- a/.github/workflows/samples-terraform.yaml +++ b/.github/workflows/samples-terraform.yaml @@ -41,6 +41,6 @@ jobs: - name: Build provider working-directory: ${{ matrix.sample }} run: go build -v ./... - - name: Run acceptance tests + - name: Run tests working-directory: ${{ matrix.sample }} - run: TF_ACC=1 go test ./... -v -timeout 120m + run: go test ./... -v -timeout 120m diff --git a/samples/client/others/terraform/allof-discriminator/.gitignore b/samples/client/others/terraform/allof-discriminator/.gitignore index 96bdf8b8acca..d948a4c42de8 100644 --- a/samples/client/others/terraform/allof-discriminator/.gitignore +++ b/samples/client/others/terraform/allof-discriminator/.gitignore @@ -8,5 +8,6 @@ *.tfstate *.tfstate.* .terraform/ -terraform.tfvars +*.tfvars +*.tfvars.json terraform-provider-allof diff --git a/samples/client/others/terraform/allof-discriminator/README.md b/samples/client/others/terraform/allof-discriminator/README.md index 3a1284d153fe..cd7dee82af68 100644 --- a/samples/client/others/terraform/allof-discriminator/README.md +++ b/samples/client/others/terraform/allof-discriminator/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.21 +- [Go](https://golang.org/doc/install) >= 1.22 ## Building The Provider @@ -39,6 +39,19 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or 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`. diff --git a/samples/client/others/terraform/allof-discriminator/go.mod b/samples/client/others/terraform/allof-discriminator/go.mod index a71d3eda02cb..f6770d9df332 100644 --- a/samples/client/others/terraform/allof-discriminator/go.mod +++ b/samples/client/others/terraform/allof-discriminator/go.mod @@ -1,6 +1,6 @@ module github.com/example/terraform-provider-allof -go 1.22 +go 1.24.0 toolchain go1.24.4 diff --git a/samples/client/others/terraform/allof-discriminator/internal/provider/provider.go b/samples/client/others/terraform/allof-discriminator/internal/provider/provider.go index 7061574fadef..8c499ac6568b 100644 --- a/samples/client/others/terraform/allof-discriminator/internal/provider/provider.go +++ b/samples/client/others/terraform/allof-discriminator/internal/provider/provider.go @@ -79,9 +79,16 @@ func (p *allofProvider) Configure(ctx context.Context, req provider.ConfigureReq return } - endpoint := config.Endpoint.ValueString() - if endpoint == "" { - endpoint = "http://localhost" + 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) diff --git a/samples/client/others/terraform/oneof-anyof-required/.gitignore b/samples/client/others/terraform/oneof-anyof-required/.gitignore index 89e30c71b4f7..4c10d2907894 100644 --- a/samples/client/others/terraform/oneof-anyof-required/.gitignore +++ b/samples/client/others/terraform/oneof-anyof-required/.gitignore @@ -8,5 +8,6 @@ *.tfstate *.tfstate.* .terraform/ -terraform.tfvars +*.tfvars +*.tfvars.json terraform-provider-oneof diff --git a/samples/client/others/terraform/oneof-anyof-required/README.md b/samples/client/others/terraform/oneof-anyof-required/README.md index 065a876d1202..fffc99f3ef06 100644 --- a/samples/client/others/terraform/oneof-anyof-required/README.md +++ b/samples/client/others/terraform/oneof-anyof-required/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.21 +- [Go](https://golang.org/doc/install) >= 1.22 ## Building The Provider @@ -39,6 +39,19 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or 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`. diff --git a/samples/client/others/terraform/oneof-anyof-required/go.mod b/samples/client/others/terraform/oneof-anyof-required/go.mod index a99cf7728b8b..4767c9e41bdf 100644 --- a/samples/client/others/terraform/oneof-anyof-required/go.mod +++ b/samples/client/others/terraform/oneof-anyof-required/go.mod @@ -1,6 +1,6 @@ module github.com/example/terraform-provider-oneof-anyof -go 1.22 +go 1.24.0 toolchain go1.24.4 diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object.go b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object.go index 580bb876145b..0aebcc2d28c0 100644 --- a/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object.go +++ b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object.go @@ -4,6 +4,6 @@ package client // Object - Object struct type Object struct { - Field1 string - Field2 string + Field1 string `json:"field1"` + Field2 string `json:"field2"` } diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object2.go b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object2.go index 340d89024501..85f4c85784a9 100644 --- a/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object2.go +++ b/samples/client/others/terraform/oneof-anyof-required/internal/client/model_object2.go @@ -4,6 +4,6 @@ package client // Object2 - Object2 struct type Object2 struct { - Field1 string - Field2 string + Field1 string `json:"field1"` + Field2 string `json:"field2"` } diff --git a/samples/client/others/terraform/oneof-anyof-required/internal/provider/provider.go b/samples/client/others/terraform/oneof-anyof-required/internal/provider/provider.go index ca100357e27e..437358f37983 100644 --- a/samples/client/others/terraform/oneof-anyof-required/internal/provider/provider.go +++ b/samples/client/others/terraform/oneof-anyof-required/internal/provider/provider.go @@ -79,9 +79,16 @@ func (p *oneofProvider) Configure(ctx context.Context, req provider.ConfigureReq return } - endpoint := config.Endpoint.ValueString() - if endpoint == "" { - endpoint = "http://localhost" + 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) diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/.gitignore b/samples/client/others/terraform/oneof-discriminator-lookup/.gitignore index 89e30c71b4f7..4c10d2907894 100644 --- a/samples/client/others/terraform/oneof-discriminator-lookup/.gitignore +++ b/samples/client/others/terraform/oneof-discriminator-lookup/.gitignore @@ -8,5 +8,6 @@ *.tfstate *.tfstate.* .terraform/ -terraform.tfvars +*.tfvars +*.tfvars.json terraform-provider-oneof diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/README.md b/samples/client/others/terraform/oneof-discriminator-lookup/README.md index b9c1b2747a7b..e1fd479793b6 100644 --- a/samples/client/others/terraform/oneof-discriminator-lookup/README.md +++ b/samples/client/others/terraform/oneof-discriminator-lookup/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.21 +- [Go](https://golang.org/doc/install) >= 1.22 ## Building The Provider @@ -39,6 +39,19 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or 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`. diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/go.mod b/samples/client/others/terraform/oneof-discriminator-lookup/go.mod index 50141f0a1815..fe32278b0259 100644 --- a/samples/client/others/terraform/oneof-discriminator-lookup/go.mod +++ b/samples/client/others/terraform/oneof-discriminator-lookup/go.mod @@ -1,6 +1,6 @@ module github.com/example/terraform-provider-oneof-disc -go 1.22 +go 1.24.0 toolchain go1.24.4 diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_object.go b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_object.go index 4cd5fef8f2f7..7a5614cb5c49 100644 --- a/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_object.go +++ b/samples/client/others/terraform/oneof-discriminator-lookup/internal/client/model_object.go @@ -4,6 +4,6 @@ package client // Object - Object struct type Object struct { - Field1 string - Type string + Field1 string `json:"field1"` + Type string `json:"type,omitempty"` } diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/internal/provider/provider.go b/samples/client/others/terraform/oneof-discriminator-lookup/internal/provider/provider.go index 14fad8f85799..8d625d154eb9 100644 --- a/samples/client/others/terraform/oneof-discriminator-lookup/internal/provider/provider.go +++ b/samples/client/others/terraform/oneof-discriminator-lookup/internal/provider/provider.go @@ -79,9 +79,16 @@ func (p *oneofProvider) Configure(ctx context.Context, req provider.ConfigureReq return } - endpoint := config.Endpoint.ValueString() - if endpoint == "" { - endpoint = "http://localhost" + 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) diff --git a/samples/client/petstore/terraform-addpet/.gitignore b/samples/client/petstore/terraform-addpet/.gitignore index f2e3600d79b0..5cc9ba00d4f9 100644 --- a/samples/client/petstore/terraform-addpet/.gitignore +++ b/samples/client/petstore/terraform-addpet/.gitignore @@ -8,5 +8,6 @@ *.tfstate *.tfstate.* .terraform/ -terraform.tfvars +*.tfvars +*.tfvars.json terraform-provider-petstore diff --git a/samples/client/petstore/terraform-addpet/README.md b/samples/client/petstore/terraform-addpet/README.md index 8cfdcf7faef5..cd476b444d3d 100644 --- a/samples/client/petstore/terraform-addpet/README.md +++ b/samples/client/petstore/terraform-addpet/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.21 +- [Go](https://golang.org/doc/install) >= 1.22 ## Building The Provider @@ -39,6 +39,19 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or 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`. diff --git a/samples/client/petstore/terraform-addpet/go.mod b/samples/client/petstore/terraform-addpet/go.mod index dbb53a1623b5..a409fb8c6db8 100644 --- a/samples/client/petstore/terraform-addpet/go.mod +++ b/samples/client/petstore/terraform-addpet/go.mod @@ -1,6 +1,6 @@ module github.com/example/terraform-provider-petstore-addpet -go 1.22 +go 1.24.0 toolchain go1.24.4 diff --git a/samples/client/petstore/terraform-addpet/internal/provider/pet_resource.go b/samples/client/petstore/terraform-addpet/internal/provider/pet_resource.go index d7e4df7a6380..337d9309f47a 100644 --- a/samples/client/petstore/terraform-addpet/internal/provider/pet_resource.go +++ b/samples/client/petstore/terraform-addpet/internal/provider/pet_resource.go @@ -114,15 +114,21 @@ func (r *PetResource) Create(ctx context.Context, req resource.CreateRequest, re } func (r *PetResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - resp.Diagnostics.AddError("Not Supported", "Read is not supported for pet") + // No read endpoint available; keep existing state as-is. } func (r *PetResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Not Supported", "Update is not supported for pet") + // 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) { - resp.Diagnostics.AddError("Not Supported", "Delete is not supported for pet") + // No delete endpoint available; remove the resource from state. } func (r *PetResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { diff --git a/samples/client/petstore/terraform-addpet/internal/provider/provider.go b/samples/client/petstore/terraform-addpet/internal/provider/provider.go index 8530d80ebfee..770a515f30ff 100644 --- a/samples/client/petstore/terraform-addpet/internal/provider/provider.go +++ b/samples/client/petstore/terraform-addpet/internal/provider/provider.go @@ -79,9 +79,16 @@ func (p *petstoreProvider) Configure(ctx context.Context, req provider.Configure return } - endpoint := config.Endpoint.ValueString() - if endpoint == "" { - endpoint = "http://petstore.swagger.io/v2" + 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) diff --git a/samples/client/petstore/terraform-server/.gitignore b/samples/client/petstore/terraform-server/.gitignore index f2e3600d79b0..5cc9ba00d4f9 100644 --- a/samples/client/petstore/terraform-server/.gitignore +++ b/samples/client/petstore/terraform-server/.gitignore @@ -8,5 +8,6 @@ *.tfstate *.tfstate.* .terraform/ -terraform.tfvars +*.tfvars +*.tfvars.json terraform-provider-petstore diff --git a/samples/client/petstore/terraform-server/README.md b/samples/client/petstore/terraform-server/README.md index fab107f97e4c..eab0fd629c1e 100644 --- a/samples/client/petstore/terraform-server/README.md +++ b/samples/client/petstore/terraform-server/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.21 +- [Go](https://golang.org/doc/install) >= 1.22 ## Building The Provider @@ -39,6 +39,19 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or 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`. diff --git a/samples/client/petstore/terraform-server/go.mod b/samples/client/petstore/terraform-server/go.mod index 1817f7399fc1..c585d873bf38 100644 --- a/samples/client/petstore/terraform-server/go.mod +++ b/samples/client/petstore/terraform-server/go.mod @@ -1,6 +1,6 @@ module github.com/example/terraform-provider-petstore-server -go 1.22 +go 1.24.0 toolchain go1.24.4 diff --git a/samples/client/petstore/terraform-server/internal/provider/fake_resource.go b/samples/client/petstore/terraform-server/internal/provider/fake_resource.go index 97ef0b158d58..a9791e3c5d06 100644 --- a/samples/client/petstore/terraform-server/internal/provider/fake_resource.go +++ b/samples/client/petstore/terraform-server/internal/provider/fake_resource.go @@ -61,15 +61,21 @@ func (r *FakeResource) Create(ctx context.Context, req resource.CreateRequest, r } func (r *FakeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - resp.Diagnostics.AddError("Not Supported", "Read is not supported for fake") + // No read endpoint available; keep existing state as-is. } func (r *FakeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Not Supported", "Update is not supported for fake") + // No update endpoint available; persist the planned values into state. + var plan FakeModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } func (r *FakeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Not Supported", "Delete is not supported for fake") + // No delete endpoint available; remove the resource from state. } func (r *FakeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { diff --git a/samples/client/petstore/terraform-server/internal/provider/pet_resource.go b/samples/client/petstore/terraform-server/internal/provider/pet_resource.go index f8ded489e27c..d4915dd1c155 100644 --- a/samples/client/petstore/terraform-server/internal/provider/pet_resource.go +++ b/samples/client/petstore/terraform-server/internal/provider/pet_resource.go @@ -139,7 +139,13 @@ func (r *PetResource) Read(ctx context.Context, req resource.ReadRequest, resp * } func (r *PetResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Not Supported", "Update is not supported for pet") + // 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) { diff --git a/samples/client/petstore/terraform-server/internal/provider/provider.go b/samples/client/petstore/terraform-server/internal/provider/provider.go index 1f13b97a4cea..c84fed6023d3 100644 --- a/samples/client/petstore/terraform-server/internal/provider/provider.go +++ b/samples/client/petstore/terraform-server/internal/provider/provider.go @@ -79,9 +79,16 @@ func (p *petstoreProvider) Configure(ctx context.Context, req provider.Configure return } - endpoint := config.Endpoint.ValueString() - if endpoint == "" { - endpoint = "http://petstore.swagger.io/v2" + 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) diff --git a/samples/client/petstore/terraform-server/internal/provider/store_resource.go b/samples/client/petstore/terraform-server/internal/provider/store_resource.go index 6795a722c124..7feca31b171e 100644 --- a/samples/client/petstore/terraform-server/internal/provider/store_resource.go +++ b/samples/client/petstore/terraform-server/internal/provider/store_resource.go @@ -61,15 +61,21 @@ func (r *StoreResource) Create(ctx context.Context, req resource.CreateRequest, } func (r *StoreResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - resp.Diagnostics.AddError("Not Supported", "Read is not supported for store") + // No read endpoint available; keep existing state as-is. } func (r *StoreResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Not Supported", "Update is not supported for store") + // No update endpoint available; persist the planned values into state. + var plan StoreModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } func (r *StoreResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Not Supported", "Delete is not supported for store") + // No delete endpoint available; remove the resource from state. } func (r *StoreResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { diff --git a/samples/client/petstore/terraform/.gitignore b/samples/client/petstore/terraform/.gitignore index f2e3600d79b0..5cc9ba00d4f9 100644 --- a/samples/client/petstore/terraform/.gitignore +++ b/samples/client/petstore/terraform/.gitignore @@ -8,5 +8,6 @@ *.tfstate *.tfstate.* .terraform/ -terraform.tfvars +*.tfvars +*.tfvars.json terraform-provider-petstore diff --git a/samples/client/petstore/terraform/README.md b/samples/client/petstore/terraform/README.md index cab12402edc5..27ed9be64720 100644 --- a/samples/client/petstore/terraform/README.md +++ b/samples/client/petstore/terraform/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.21 +- [Go](https://golang.org/doc/install) >= 1.22 ## Building The Provider @@ -39,6 +39,19 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or 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" = "${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`. diff --git a/samples/client/petstore/terraform/go.mod b/samples/client/petstore/terraform/go.mod index 1e0e9158140f..c88995b9897c 100644 --- a/samples/client/petstore/terraform/go.mod +++ b/samples/client/petstore/terraform/go.mod @@ -1,6 +1,6 @@ module github.com/example/terraform-provider-petstore -go 1.22 +go 1.24.0 toolchain go1.24.4 diff --git a/samples/client/petstore/terraform/internal/provider/pet_resource.go b/samples/client/petstore/terraform/internal/provider/pet_resource.go index 6b4667ec3eec..066e02e939cb 100644 --- a/samples/client/petstore/terraform/internal/provider/pet_resource.go +++ b/samples/client/petstore/terraform/internal/provider/pet_resource.go @@ -139,7 +139,13 @@ func (r *PetResource) Read(ctx context.Context, req resource.ReadRequest, resp * } func (r *PetResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Not Supported", "Update is not supported for pet") + // 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) { diff --git a/samples/client/petstore/terraform/internal/provider/provider.go b/samples/client/petstore/terraform/internal/provider/provider.go index 108b70ec94dd..ea03fe4b3cbb 100644 --- a/samples/client/petstore/terraform/internal/provider/provider.go +++ b/samples/client/petstore/terraform/internal/provider/provider.go @@ -79,9 +79,16 @@ func (p *petstoreProvider) Configure(ctx context.Context, req provider.Configure return } - endpoint := config.Endpoint.ValueString() - if endpoint == "" { - endpoint = "http://petstore.swagger.io/v2" + 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) diff --git a/samples/client/petstore/terraform/internal/provider/store_resource.go b/samples/client/petstore/terraform/internal/provider/store_resource.go index 8a12609e4c19..dc7fa689dbcc 100644 --- a/samples/client/petstore/terraform/internal/provider/store_resource.go +++ b/samples/client/petstore/terraform/internal/provider/store_resource.go @@ -61,15 +61,21 @@ func (r *StoreResource) Create(ctx context.Context, req resource.CreateRequest, } func (r *StoreResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - resp.Diagnostics.AddError("Not Supported", "Read is not supported for store") + // No read endpoint available; keep existing state as-is. } func (r *StoreResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Not Supported", "Update is not supported for store") + // No update endpoint available; persist the planned values into state. + var plan StoreModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } func (r *StoreResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Not Supported", "Delete is not supported for store") + // No delete endpoint available; remove the resource from state. } func (r *StoreResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { From f570e8b60c63c301f9cc6a67f9c054e2f7fa0ffd Mon Sep 17 00:00:00 2001 From: Jason D'Amour Date: Thu, 12 Feb 2026 22:22:53 +0000 Subject: [PATCH 7/7] chore: docs --- docs/generators.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/generators.md b/docs/generators.md index bfa97dd22e54..930bdbd80304 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -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)