Sobes.tech
Senior

Как создать собственный провайдер в Terraform?

sobes.tech AI

Answer from AI

To create your own provider in Terraform:

  1. Choose a language: Usually Go, as Terraform is written in Go and provides convenient SDKs.
  2. Set up the workspace: Create a new project and initialize a Go module.
  3. Create the provider structure:
    • main.go file: Entry point where the provider is registered.
    • Files for resources and/or data sources: Describe the logic for create, read, update, delete (CRUD) for each resource and read logic for each data source.
  4. Implement interfaces:
    • Create a structure implementing the provider.Provider interface.
    • For each resource, create a structure implementing the resource.Resource interface.
    • For each data source, create a structure implementing the datasource.DataSource interface.
  5. Define schema: Inside resource and data source structures, define the data schema (type, required, description of each field).
  6. Implement CRUD/read operations: Write logic for each operation:
    • Create: Create resource.
    • Read: Read resource/data source state.
    • Update: Update resource.
    • Delete: Delete resource.
    • Exists: Check if resource exists (optional but recommended).
  7. Error handling: Implement proper error handling at all stages.
  8. Build and install: Compile the provider and place the executable in the appropriate Terraform plugins directory (~/.terraform.d/plugins/ or the directory specified in the configuration).
  9. Testing: Write tests to verify provider functionality.
package main

import (
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
)

func Provider() *schema.Provider {
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"endpoint": { // Example provider configuration field
				Type:        schema.TypeString,
				Optional:    true,
				DefaultFunc: schema.EnvDefaultFunc("MYPROVIDER_ENDPOINT", nil),
				Description: "The endpoint for the MyProvider API.",
			},
		},
		ResourcesMap: map[string]*schema.Resource{
			"myprovider_resource": resourceMyProviderResource(), // Register resource
		},
		DataSourcesMap: map[string]*schema.Resource{
			"myprovider_datasource": dataSourceMyProviderDataSource(), // Register data source
		},
		ConfigureFunc: providerConfigure,
	}
}

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
	endpoint := d.Get("endpoint").(string)
	// Create API client or structure for external system interaction
	client := &MyProviderClient{Endpoint: endpoint} // Example: MyProviderClient - your custom structure
	return client, nil
}

func main() {
	plugin.Serve(&plugin.ServeOpts{
		ProviderFunc: Provider,
	})
}

package main

import (
	"context"
	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceMyProviderResource() *schema.Resource {
	return &schema.Resource{
		CreateContext: resourceMyProviderResourceCreate,
		ReadContext:   resourceMyProviderResourceRead,
		UpdateContext: resourceMyProviderResourceUpdate,
		DeleteContext: resourceMyProviderResourceDelete,
		ExistsContext: resourceMyProviderResourceExists, // Optional
		Importer: &schema.ResourceImporter{
			StateContext: schema.ImportStatePassthroughContext,
		},
		Schema: map[string]*schema.Schema{
			"name": { // Example resource field
				Type:        schema.TypeString,
				Required:    true,
				Description: "The name of the resource.",
			},
			"value": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The value of the resource.",
			},
		},
	}
}

// Implement CRUD and Exists context functions
func resourceMyProviderResourceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	// Get client from m
	// Get data from d
	// Call API to create resource
	// Set resource ID d.SetId("...")
	// Return diag.FromErr(err) or nil
	return diag.Errorf("Create not implemented")
}

func resourceMyProviderResourceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	// Get client from m
	// Get resource ID d.Id()
	// Call API to read resource state
	// Update data in d.Set("name", ...)
	// If resource not found, d.SetId("")
	// Return diag.FromErr(err) or nil
	return diag.Errorf("Read not implemented")
}

func resourceMyProviderResourceUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	// Get client from m
	// Get resource ID d.Id() and data from d
	// Call API to update resource
	// Return diag.FromErr(err) or nil
	return diag.Errorf("Update not implemented")
}

func resourceMyProviderResourceDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	// Get client from m
	// Get resource ID d.Id()
	// Call API to delete resource
	// Return diag.FromErr(err) or nil
	return diag.Errorf("Delete not implemented")
}

func resourceMyProviderResourceExists(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, diag.Diagnostics) {
	// Get client from m
	// Get resource ID d.Id()
	// Call API to check if resource exists
	// Return bool (exists) and diag.FromErr(err) or nil
	return false, diag.Errorf("Exists not implemented")
}