diff --git a/.env b/.env new file mode 100644 index 0000000..168b6a1 --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +ADGUARD_HOST="localhost:8080" +ADGUARD_USERNAME="admin" +ADGUARD_PASSWORD="SecretP@ssw0rd" +ADGUARD_SCHEME="http" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3dea6ba --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,41 @@ +# Terraform Provider release workflow. +name: Release + +# This GitHub action creates a release when a tag that matches the pattern +# "v*" (e.g. v0.1.0) is created. +on: + push: + tags: + - "v*" + +# Releases need permissions to read and write the repository contents. +# GitHub considers creating releases and uploading assets as writing contents. +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + with: + # Allow goreleaser to access older tag information. + fetch-depth: 0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + with: + go-version-file: "go.mod" + cache: true + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@111c56156bcc6918c056dbef52164cfa583dc549 # v5.2.0 + id: import_gpg + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.PASSPHRASE }} + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@f82d6c1c344bcacabba2c841718984797f664a6b # v4.2.0 + with: + args: release --clean + env: + # GitHub sets the GITHUB_TOKEN secret automatically. + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} diff --git a/.gitignore b/.gitignore index 66fd13c..77f3539 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +# Terraform +.terraform* +terraform.tfstate* diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..c2c6bb3 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,60 @@ +# Visit https://goreleaser.com for documentation on how to customize this +# behavior. +before: + hooks: + # this is just an example and not a requirement for provider building/publishing + - go mod tidy +builds: + - env: + # goreleaser does not work with CGO, it could also complicate + # usage by users in CI/CD systems like Terraform Cloud where + # they are unable to install libraries. + - CGO_ENABLED=0 + mod_timestamp: "{{ .CommitTimestamp }}" + flags: + - -trimpath + ldflags: + - "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}" + goos: + - freebsd + - windows + - linux + - darwin + goarch: + - amd64 + - "386" + - arm + - arm64 + ignore: + - goos: darwin + goarch: "386" + binary: "{{ .ProjectName }}_v{{ .Version }}" +archives: + - format: zip + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" +checksum: + extra_files: + - glob: "terraform-registry-manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_SHA256SUMS" + algorithm: sha256 +signs: + - artifacts: checksum + args: + # if you are using this in a GitHub action or some other automated pipeline, you + # need to pass the batch flag to indicate its not interactive. + - "--batch" + - "--local-user" + - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key + - "--output" + - "${signature}" + - "--detach-sign" + - "${artifact}" +release: + extra_files: + - glob: "terraform-registry-manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_manifest.json" + # If you want to manually examine the release before its live, uncomment this line: + # draft: true +changelog: + skip: true diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..05d7e4c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "All tests", + "type": "go", + "request": "launch", + "mode": "test", + "buildFlags": "-v -tags=all", + "program": "${workspaceFolder}/adguard", + "env": { + "TF_ACC": "1" + }, + "envFile": "${workspaceFolder}/.env", + "showLog": true + }, + { + "name": "Attach to process", + "type": "go", + "request": "attach", + "mode": "local", + "processId": 1234 + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e5fe137 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "go.testFlags": ["-v", "-tags=all", "-args", "-test.v"], + "go.testEnvVars": { + "TF_ACC": "1" + }, + "go.testEnvFile": "${workspaceFolder}/.env", + "[go]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": true + } + }, + "gopls": { + "env": { + "GOFLAGS": "-tags=all" + }, + "usePlaceholders": true, // add parameter placeholders when completing a function + // Experimental settings + "completeUnimported": true, // autocomplete unimported packages + "deepCompletion": true // enable deep completion + }, +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..742c4c4 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +TEST?=$$(go list ./... | grep -v 'vendor') +HOSTNAME=registry.terraform.io +NAMESPACE=gmichels +NAME=adguard +BINARY=terraform-provider-${NAME} +VERSION=0.1.0 +OS_ARCH=darwin_amd64 + +default: install + +build: + go build -o ${BINARY} + +release: + GOOS=darwin GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_darwin_amd64 + GOOS=freebsd GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_freebsd_386 + GOOS=freebsd GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_freebsd_amd64 + GOOS=freebsd GOARCH=arm go build -o ./bin/${BINARY}_${VERSION}_freebsd_arm + GOOS=linux GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_linux_386 + GOOS=linux GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_linux_amd64 + GOOS=linux GOARCH=arm go build -o ./bin/${BINARY}_${VERSION}_linux_arm + GOOS=openbsd GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_openbsd_386 + GOOS=openbsd GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_openbsd_amd64 + GOOS=solaris GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_solaris_amd64 + GOOS=windows GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_windows_386 + GOOS=windows GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_windows_amd64 + +install: build + mkdir -p ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} + mv ${BINARY} ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} + +test: + go test -i $(TEST) || exit 1 + echo $(TEST) | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 + +testacc: + TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 120m diff --git a/README.md b/README.md new file mode 100644 index 0000000..34762bb --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# AdGuard Home Terraform Provider (terraform-provider-adguard) + +**WARNING** under development + +Functionality first needs to be added to the [adguard-client-go](https://github.com/gmichels/adguard-client-go) SDK. + +# Documentation + +You can browse documentation under the [docs](docs) folder. diff --git a/adguard/client_data_source.go b/adguard/client_data_source.go new file mode 100644 index 0000000..3c4539a --- /dev/null +++ b/adguard/client_data_source.go @@ -0,0 +1,180 @@ +package adguard + +import ( + "context" + + "github.com/gmichels/adguard-client-go" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// ensure the implementation satisfies the expected interfaces +var ( + _ datasource.DataSource = &clientDataSource{} + _ datasource.DataSourceWithConfigure = &clientDataSource{} +) + +// clientDataSource is the data source implementation +type clientDataSource struct { + adg *adguard.ADG +} + +// clientDataModel maps client schema data +type clientDataModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Ids types.List `tfsdk:"ids"` + UseGlobalSettings types.Bool `tfsdk:"use_global_settings"` + FilteringEnabled types.Bool `tfsdk:"filtering_enabled"` + ParentalEnabled types.Bool `tfsdk:"parental_enabled"` + SafebrowsingEnabled types.Bool `tfsdk:"safebrowsing_enabled"` + SafesearchEnabled types.Bool `tfsdk:"safesearch_enabled"` + UseGlobalBlockedServices types.Bool `tfsdk:"use_global_blocked_services"` + BlockedServices types.List `tfsdk:"blocked_services"` + Upstreams types.List `tfsdk:"upstreams"` + Tags types.List `tfsdk:"tags"` +} + +// NewClientDataSource is a helper function to simplify the provider implementation +func NewClientDataSource() datasource.DataSource { + return &clientDataSource{} +} + +// Metadata returns the data source type name +func (d *clientDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_client" +} + +// Schema defines the schema for the data source +func (d *clientDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Placeholder identifier attribute", + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "Name of the client", + Required: true, + }, + "ids": schema.ListAttribute{ + Description: "List of identifiers for this client (IP, CIDR, MAC, or ClientID)", + ElementType: types.StringType, + Optional: true, + }, + "use_global_settings": schema.BoolAttribute{ + Description: "Whether to use global settings on this client", + Optional: true, + }, + "filtering_enabled": schema.BoolAttribute{ + Description: "Whether to have filtering enabled on this client", + Optional: true, + }, + "parental_enabled": schema.BoolAttribute{ + Description: "Whether to have AdGuard parental controls enabled on this client", + Optional: true, + }, + "safebrowsing_enabled": schema.BoolAttribute{ + Description: "Whether to have AdGuard browsing security enabled on this client", + Optional: true, + }, + "safesearch_enabled": schema.BoolAttribute{ + Description: "Whether to enforce safe search on this client", + Optional: true, + }, + "use_global_blocked_services": schema.BoolAttribute{ + Description: "Whether to use global settings for blocked services", + Optional: true, + }, + "blocked_services": schema.ListAttribute{ + Description: "List of blocked services for this client", + ElementType: types.StringType, + Optional: true, + }, + "upstreams": schema.ListAttribute{ + Description: "List of upstream DNS server for this client", + ElementType: types.StringType, + Optional: true, + }, + "tags": schema.ListAttribute{ + Description: "List of tags for this client", + ElementType: types.StringType, + Optional: true, + }, + }, + } +} + +// Read refreshes the Terraform state with the latest data +func (d *clientDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + // read Terraform configuration data into the model + var state clientDataModel + diags := req.Config.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + + // retrieve client info + client, err := d.adg.GetClient(state.Name.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Unable to Read AdGuard Home Client", + err.Error(), + ) + return + } + if client == nil { + resp.Diagnostics.AddError( + "Unable to Locate AdGuard Home Client", + "No client with name `"+state.Name.ValueString()+"` exists in AdGuard Home.", + ) + return + } + + // map response body to model + state.Name = types.StringValue(client.Name) + state.Ids, diags = types.ListValueFrom(ctx, types.StringType, client.Ids) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + state.UseGlobalSettings = types.BoolValue(client.UseGlobalSettings) + state.FilteringEnabled = types.BoolValue(client.FilteringEnabled) + state.ParentalEnabled = types.BoolValue(client.ParentalEnabled) + state.SafebrowsingEnabled = types.BoolValue(client.SafebrowsingEnabled) + state.SafesearchEnabled = types.BoolValue(client.SafesearchEnabled) + state.UseGlobalBlockedServices = types.BoolValue(client.UseGlobalBlockedServices) + state.BlockedServices, diags = types.ListValueFrom(ctx, types.StringType, client.BlockedServices) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + state.Upstreams, diags = types.ListValueFrom(ctx, types.StringType, client.Upstreams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + state.Tags, diags = types.ListValueFrom(ctx, types.StringType, client.Tags) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // set ID placeholder for testing + state.ID = types.StringValue("placeholder") + + // set state + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Configure adds the provider configured client to the data source +func (d *clientDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + d.adg = req.ProviderData.(*adguard.ADG) +} diff --git a/adguard/client_data_source_test.go b/adguard/client_data_source_test.go new file mode 100644 index 0000000..021267a --- /dev/null +++ b/adguard/client_data_source_test.go @@ -0,0 +1,30 @@ +package adguard + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccClientDataSource(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Read testing + { + Config: providerConfig + `data "adguard_client" "test" { name = "Test Client Data Source" }`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.adguard_client.test", "name", "Test Client Data Source"), + resource.TestCheckResourceAttr("data.adguard_client.test", "ids.#", "1"), + resource.TestCheckResourceAttr("data.adguard_client.test", "ids.0", "192.168.100.100"), + resource.TestCheckResourceAttr("data.adguard_client.test", "tags.0", "device_other"), + resource.TestCheckResourceAttr("data.adguard_client.test", "use_global_settings", "true"), + resource.TestCheckResourceAttr("data.adguard_client.test", "use_global_blocked_services", "true"), + + // Verify placeholder id attribute + resource.TestCheckResourceAttr("data.adguard_client.test", "id", "placeholder"), + ), + }, + }, + }) +} diff --git a/adguard/client_resource.go b/adguard/client_resource.go new file mode 100644 index 0000000..9c69649 --- /dev/null +++ b/adguard/client_resource.go @@ -0,0 +1,411 @@ +package adguard + +import ( + "context" + "time" + + "github.com/gmichels/adguard-client-go" + "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/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/terraform-community-providers/terraform-plugin-framework-utils/modifiers" +) + +// ensure the implementation satisfies the expected interfaces +var ( + _ resource.Resource = &clientResource{} + _ resource.ResourceWithConfigure = &clientResource{} + _ resource.ResourceWithImportState = &clientResource{} +) + +// clientResource is the resource implementation +type clientResource struct { + adg *adguard.ADG +} + +// clientResourceModel maps client schema data +type clientResourceModel struct { + ID types.String `tfsdk:"id"` + LastUpdated types.String `tfsdk:"last_updated"` + Name types.String `tfsdk:"name"` + Ids types.List `tfsdk:"ids"` + UseGlobalSettings types.Bool `tfsdk:"use_global_settings"` + FilteringEnabled types.Bool `tfsdk:"filtering_enabled"` + ParentalEnabled types.Bool `tfsdk:"parental_enabled"` + SafebrowsingEnabled types.Bool `tfsdk:"safebrowsing_enabled"` + SafesearchEnabled types.Bool `tfsdk:"safesearch_enabled"` + UseGlobalBlockedServices types.Bool `tfsdk:"use_global_blocked_services"` + BlockedServices types.List `tfsdk:"blocked_services"` + Upstreams types.List `tfsdk:"upstreams"` + Tags types.List `tfsdk:"tags"` +} + +// NewClientResource is a helper function to simplify the provider implementation +func NewClientResource() resource.Resource { + return &clientResource{} +} + +// Metadata returns the resource type name +func (r *clientResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_client" +} + +// Schema defines the schema for the resource +func (r *clientResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Internal identifier for this client", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "last_updated": schema.StringAttribute{ + Description: "Timestamp of the last Terraform update of the client", + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "Name of the client", + Required: true, + }, + "ids": schema.ListAttribute{ + Description: "List of identifiers for this client (IP, CIDR, MAC, or ClientID)", + ElementType: types.StringType, + Required: true, + }, + // default values are not yet an easy task using the plugin framework + // see https://github.com/hashicorp/terraform-plugin-framework/issues/668 + // using instead https://github.com/terraform-community-providers/terraform-plugin-framework-utils/modifiers + "use_global_settings": schema.BoolAttribute{ + Description: "Whether to use global settings on this client", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.Bool{ + modifiers.DefaultBool(true), + }, + }, + "filtering_enabled": schema.BoolAttribute{ + Description: "Whether to have filtering enabled on this client", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.Bool{ + modifiers.DefaultBool(false), + }, + }, + "parental_enabled": schema.BoolAttribute{ + Description: "Whether to have AdGuard parental controls enabled on this client", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.Bool{ + modifiers.DefaultBool(false), + }, + }, + "safebrowsing_enabled": schema.BoolAttribute{ + Description: "Whether to have AdGuard browsing security enabled on this client", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.Bool{ + modifiers.DefaultBool(false), + }, + }, + "safesearch_enabled": schema.BoolAttribute{ + Description: "Whether to enforce safe search on this client", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.Bool{ + modifiers.DefaultBool(false), + }, + }, + "use_global_blocked_services": schema.BoolAttribute{ + Description: "Whether to use global settings for blocked services", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.Bool{ + modifiers.DefaultBool(true), + }, + }, + "blocked_services": schema.ListAttribute{ + Description: "List of blocked services for this client", + ElementType: types.StringType, + Optional: true, + }, + "upstreams": schema.ListAttribute{ + Description: "List of upstream DNS server for this client", + ElementType: types.StringType, + Optional: true, + }, + "tags": schema.ListAttribute{ + Description: "List of tags for this client", + ElementType: types.StringType, + Optional: true, + }, + }, + } +} + +// Configure adds the provider configured client to the resource +func (r *clientResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.adg = req.ProviderData.(*adguard.ADG) +} + +// Create creates the resource and sets the initial Terraform state +func (r *clientResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // retrieve values from plan + var plan clientResourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // instantiate empty client for storing plan data + var clientPlan adguard.Client + + // populate client from plan + clientPlan.Name = plan.Name.ValueString() + diags = plan.Ids.ElementsAs(ctx, &clientPlan.Ids, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + clientPlan.UseGlobalSettings = plan.UseGlobalSettings.ValueBool() + clientPlan.FilteringEnabled = plan.FilteringEnabled.ValueBool() + clientPlan.ParentalEnabled = plan.ParentalEnabled.ValueBool() + clientPlan.SafebrowsingEnabled = plan.SafebrowsingEnabled.ValueBool() + clientPlan.SafesearchEnabled = plan.SafesearchEnabled.ValueBool() + clientPlan.UseGlobalBlockedServices = plan.UseGlobalBlockedServices.ValueBool() + if len(plan.BlockedServices.Elements()) > 0 { + diags = plan.BlockedServices.ElementsAs(ctx, &clientPlan.BlockedServices, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + if len(plan.Upstreams.Elements()) > 0 { + diags = plan.Upstreams.ElementsAs(ctx, &clientPlan.Upstreams, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + if len(plan.Tags.Elements()) > 0 { + diags = plan.Tags.ElementsAs(ctx, &clientPlan.Tags, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + + // create new clientState using plan + clientState, err := r.adg.CreateClient(clientPlan) + if err != nil { + resp.Diagnostics.AddError( + "Error creating client", + "Could not create client, unexpected error: "+err.Error(), + ) + return + } + + // map response body to schema and populate Computed attribute values + plan.ID = types.StringValue(clientState.Name) + plan.Name = types.StringValue(clientState.Name) + plan.Ids, diags = types.ListValueFrom(ctx, types.StringType, clientState.Ids) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + plan.UseGlobalSettings = types.BoolValue(clientState.UseGlobalSettings) + plan.FilteringEnabled = types.BoolValue(clientState.FilteringEnabled) + plan.ParentalEnabled = types.BoolValue(clientState.ParentalEnabled) + plan.SafebrowsingEnabled = types.BoolValue(clientState.SafebrowsingEnabled) + plan.SafesearchEnabled = types.BoolValue(clientState.SafesearchEnabled) + plan.UseGlobalBlockedServices = types.BoolValue(clientState.UseGlobalBlockedServices) + if len(clientState.BlockedServices) > 0 { + plan.BlockedServices, diags = types.ListValueFrom(ctx, types.StringType, clientState.BlockedServices) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + plan.Upstreams, diags = types.ListValueFrom(ctx, types.StringType, clientState.Upstreams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + plan.Tags, diags = types.ListValueFrom(ctx, types.StringType, clientState.Tags) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // add the last updated attribute + plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) + + // set state to fully populated data + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Read refreshes the Terraform state with the latest data +func (r *clientResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + // get current state + var state clientResourceModel + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // get refreshed client value from AdGuard Home + client, err := r.adg.GetClient(state.ID.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Error Reading AdGuard Home Client", + "Could not read AdGuard Home client ID "+state.ID.ValueString()+": "+err.Error(), + ) + return + } + + // overwrite client with refreshed state + state.Name = types.StringValue(client.Name) + state.Ids, diags = types.ListValueFrom(ctx, types.StringType, client.Ids) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + state.UseGlobalSettings = types.BoolValue(client.UseGlobalSettings) + state.FilteringEnabled = types.BoolValue(client.FilteringEnabled) + state.ParentalEnabled = types.BoolValue(client.ParentalEnabled) + state.SafebrowsingEnabled = types.BoolValue(client.SafebrowsingEnabled) + state.SafesearchEnabled = types.BoolValue(client.SafesearchEnabled) + state.UseGlobalBlockedServices = types.BoolValue(client.UseGlobalBlockedServices) + state.BlockedServices, diags = types.ListValueFrom(ctx, types.StringType, client.BlockedServices) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + state.Upstreams, diags = types.ListValueFrom(ctx, types.StringType, client.Upstreams) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + state.Tags, diags = types.ListValueFrom(ctx, types.StringType, client.Tags) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // set refreshed state + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Update updates the resource and sets the updated Terraform state on success +func (r *clientResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + // retrieve values from plan + var plan clientResourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // generate API request body from plan + var clientUpdate adguard.ClientUpdate + clientUpdate.Name = plan.Name.ValueString() + clientUpdate.Data.Name = plan.Name.ValueString() + diags = plan.Ids.ElementsAs(ctx, &clientUpdate.Data.Ids, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + clientUpdate.Data.UseGlobalSettings = plan.UseGlobalSettings.ValueBool() + clientUpdate.Data.FilteringEnabled = plan.FilteringEnabled.ValueBool() + clientUpdate.Data.ParentalEnabled = plan.ParentalEnabled.ValueBool() + clientUpdate.Data.SafebrowsingEnabled = plan.SafebrowsingEnabled.ValueBool() + clientUpdate.Data.SafesearchEnabled = plan.SafesearchEnabled.ValueBool() + clientUpdate.Data.UseGlobalBlockedServices = plan.UseGlobalBlockedServices.ValueBool() + if len(plan.BlockedServices.Elements()) > 0 { + diags = plan.BlockedServices.ElementsAs(ctx, &clientUpdate.Data.BlockedServices, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + if len(plan.Upstreams.Elements()) > 0 { + diags = plan.Upstreams.ElementsAs(ctx, &clientUpdate.Data.Upstreams, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + if len(plan.Tags.Elements()) > 0 { + diags = plan.Tags.ElementsAs(ctx, &clientUpdate.Data.Tags, false) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } + + // update existing client + _, err := r.adg.UpdateClient(clientUpdate) + if err != nil { + resp.Diagnostics.AddError( + "Error Updating AdGuard Home Client", + "Could not update client, unexpected error: "+err.Error(), + ) + return + } + + // update resource state with updated items and timestamp + plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) + + // update state + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Delete deletes the resource and removes the Terraform state on success +func (r *clientResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // retrieve values from state + var state clientResourceModel + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + var clientDelete adguard.ClientDelete + clientDelete.Name = state.ID.ValueString() + // delete existing client + err := r.adg.DeleteClient(clientDelete) + if err != nil { + resp.Diagnostics.AddError( + "Error Deleting AdGuard Home Client", + "Could not delete client, unexpected error: "+err.Error(), + ) + return + } +} + +func (r *clientResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + // retrieve import ID and save to id attribute + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/adguard/client_resource_test.go b/adguard/client_resource_test.go new file mode 100644 index 0000000..2dc19ea --- /dev/null +++ b/adguard/client_resource_test.go @@ -0,0 +1,55 @@ +package adguard + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccClientResource(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: providerConfig + ` +resource "adguard_client" "test" { + name = "Test Client" + ids = ["192.168.100.15", "test-client"] +} +`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("adguard_client.test", "name", "Test Client"), + resource.TestCheckResourceAttr("adguard_client.test", "ids.#", "2"), + resource.TestCheckResourceAttr("adguard_client.test", "ids.1", "test-client"), + // Verify dynamic values have any value set in the state. + resource.TestCheckResourceAttrSet("adguard_client.test", "id"), + resource.TestCheckResourceAttrSet("adguard_client.test", "last_updated"), + ), + }, + // ImportState testing + { + ResourceName: "adguard_client.test", + ImportState: true, + ImportStateVerify: true, + // The last_updated attribute does not exist in AdGuard Home, + // therefore there is no value for it during import + ImportStateVerifyIgnore: []string{"last_updated"}, + }, + // Update and Read testing + { + Config: providerConfig + ` +resource "adguard_client" "test" { + name = "Test Client" + ids = ["192.168.100.15", "test-client", "another-test-client"] +} +`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("adguard_client.test", "ids.#", "3"), + resource.TestCheckResourceAttr("adguard_client.test", "ids.2", "another-test-client"), + ), + }, + // Delete testing automatically occurs in TestCase + }, + }) +} diff --git a/adguard/provider.go b/adguard/provider.go new file mode 100644 index 0000000..67f491b --- /dev/null +++ b/adguard/provider.go @@ -0,0 +1,293 @@ +package adguard + +import ( + "context" + "os" + "regexp" + "strconv" + + "github.com/gmichels/adguard-client-go" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/path" + "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/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// define a max AdGuard Home client timeout +const MAX_TIMEOUT int = 60 + +// ensure the implementation satisfies the expected interfaces +var ( + _ provider.Provider = &adguardProvider{} +) + +// New is a helper function to simplify provider server and testing implementation +func New() provider.Provider { + return &adguardProvider{} +} + +// adguardProvider is the provider implementation +type adguardProvider struct{} + +// Metadata returns the provider type name +func (p *adguardProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) { + resp.TypeName = "adguard" +} + +// Schema defines the provider-level schema for configuration data +func (p *adguardProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "host": schema.StringAttribute{ + Description: "The hostname of the AdGuard Home instance. Include the port if not on a standard HTTP/HTTPS port", + Optional: true, + }, + "username": schema.StringAttribute{ + Description: "The username of the AdGuard Home instance", + Optional: true, + }, + "password": schema.StringAttribute{ + Description: "The password of the AdGuard Home instance", + Optional: true, + Sensitive: true, + }, + "scheme": schema.StringAttribute{ + Description: "The HTTP scheme of the AdGuard Home instance. Can be either `http` or `https` (default)", + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(4, 5), + stringvalidator.RegexMatches( + regexp.MustCompile(`^https{0,1}$`), + "must be either http or https", + ), + }, + }, + "timeout": schema.Int64Attribute{ + Description: "The timeout (in seconds) for making requests to AdGuard Home. Defaults to **10**", + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, int64(MAX_TIMEOUT)), + }, + }, + }, + } +} + +// adguardProviderModel maps provider schema data to a Go type +type adguardProviderModel struct { + Host types.String `tfsdk:"host"` + Username types.String `tfsdk:"username"` + Password types.String `tfsdk:"password"` + Scheme types.String `tfsdk:"scheme"` + Timeout types.Int64 `tfsdk:"timeout"` +} + +// Configure prepares an AdGuard API client for data sources and resources +func (p *adguardProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + tflog.Info(ctx, "Configuring AdGuard Home client") + + var config adguardProviderModel + + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + + if resp.Diagnostics.HasError() { + return + } + + // if provided a configuration value for any of the attributes, it must be a known value + if config.Host.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("host"), + "Unknown AdGuard Home Host", + "The provider cannot create the AdGuard Home client as there is an unknown configuration value for the AdGuard Home host. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or use the ADGUARD_HOST environment variable.", + ) + } + + if config.Username.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("username"), + "Unknown AdGuard Home Username", + "The provider cannot create the AdGuard Home client as there is an unknown configuration value for the AdGuard Home username. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or use the ADGUARD_USERNAME environment variable.", + ) + } + + if config.Password.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("password"), + "Unknown AdGuard Home Password", + "The provider cannot create the AdGuard Home client as there is an unknown configuration value for the AdGuard Home password. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or use the ADGUARD_PASSWORD environment variable.", + ) + } + + if config.Scheme.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("scheme"), + "Unknown AdGuard Home Scheme", + "The provider cannot create the AdGuard Home client as there is an unknown configuration value for the AdGuard Home scheme. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or use the ADGUARD_SCHEME environment variable.", + ) + } + + if config.Timeout.IsUnknown() { + resp.Diagnostics.AddAttributeError( + path.Root("timeout"), + "Unknown AdGuard Home Timeout", + "The provider cannot create the AdGuard Home client as there is an unknown configuration value for the AdGuard Home timeout. "+ + "Either target apply the source of the value first, set the value statically in the configuration, or use the ADGUARD_TIMEOUT environment variable.", + ) + } + + if resp.Diagnostics.HasError() { + return + } + + // default values to environment variables, but override with Terraform configuration value if set + host := os.Getenv("ADGUARD_HOST") + username := os.Getenv("ADGUARD_USERNAME") + password := os.Getenv("ADGUARD_PASSWORD") + scheme := os.Getenv("ADGUARD_SCHEME") + // sanity check for scheme when provided via env variable + if scheme != "" && scheme != "http" && scheme != "https" { + resp.Diagnostics.AddAttributeError( + path.Root("scheme"), + "Unable to parse AdGuard Home Scheme value", + "The provider cannot create the AdGuard Home client as the provided value for ADGUARD_SCHEME needs to be either `http` or `https`.") + return + } + timeout_env := os.Getenv("ADGUARD_TIMEOUT") + // sanity check for timeout when provided via env variable + var timeout int + if timeout_env != "" { + var err error + timeout, err = strconv.Atoi(timeout_env) + if err != nil { + resp.Diagnostics.AddAttributeError( + path.Root("timeout"), + "Unable to parse AdGuard Home Timeout value", + "The provider cannot create the AdGuard Home client as it was unable to parse the provided value for ADGUARD_TIMEOUT.") + return + } else if timeout <= 0 || timeout > MAX_TIMEOUT { + resp.Diagnostics.AddAttributeError( + path.Root("timeout"), + "Unable to parse AdGuard Home Timeout value", + "The provider cannot create the AdGuard Home client as the provided value for ADGUARD_TIMEOUT was outside the acceptable range (1, "+strconv.Itoa(MAX_TIMEOUT)+").") + return + } + } + + if !config.Host.IsNull() { + host = config.Host.ValueString() + } + + if !config.Username.IsNull() { + username = config.Username.ValueString() + } + + if !config.Password.IsNull() { + password = config.Password.ValueString() + } + + if !config.Scheme.IsNull() { + scheme = config.Scheme.ValueString() + } + + if !config.Timeout.IsNull() { + timeout = int(config.Timeout.ValueInt64()) + } + + // if any of the expected configurations are missing, return errors with provider-specific guidance + if host == "" { + resp.Diagnostics.AddAttributeError( + path.Root("host"), + "Missing AdGuard Home Host", + "The provider cannot create the AdGuard Home client as there is a missing or empty value for the AdGuard Home host. "+ + "Set the host value in the configuration or use the ADGUARD_HOST environment variable. "+ + "If either is already set, ensure the value is not empty.", + ) + } + + if username == "" { + resp.Diagnostics.AddAttributeError( + path.Root("username"), + "Missing AdGuard Home Username", + "The provider cannot create the AdGuard Home client as there is a missing or empty value for the AdGuard Home username. "+ + "Set the username value in the configuration or use the ADGUARD_USERNAME environment variable. "+ + "If either is already set, ensure the value is not empty.", + ) + } + + if password == "" { + resp.Diagnostics.AddAttributeError( + path.Root("password"), + "Missing AdGuard Home Password", + "The provider cannot create the AdGuard Home client as there is a missing or empty value for the AdGuard Home password. "+ + "Set the password value in the configuration or use the ADGUARD_PASSWORD environment variable. "+ + "If either is already set, ensure the value is not empty.", + ) + } + + if scheme == "" { + // default to https + scheme = "https" + } + + if timeout == 0 { + // default to 10 seconds + timeout = 10 + } + + if resp.Diagnostics.HasError() { + return + } + + ctx = tflog.SetField(ctx, "adguard_host", host) + ctx = tflog.SetField(ctx, "adguard_username", username) + ctx = tflog.SetField(ctx, "adguard_password", password) + ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "adguard_password") + ctx = tflog.SetField(ctx, "adguard_scheme", scheme) + ctx = tflog.SetField(ctx, "adguard_timeout", timeout) + + tflog.Debug(ctx, "Creating AdGuard Home client") + + // create a new AdGuard Home client using the configuration values + client, err := adguard.NewClient(&host, &username, &password, &scheme, &timeout) + if err != nil { + resp.Diagnostics.AddError( + "Unable to Create AdGuard Home Client", + "An unexpected error occurred when creating the AdGuard Home client. "+ + "If the error is not clear, please contact the provider developers.\n\n"+ + "AdGuard Home Client Error: "+err.Error(), + ) + return + } + + // make the AdGuard Home client available during DataSource and Resource type Configure methods + resp.DataSourceData = client + resp.ResourceData = client + + tflog.Info(ctx, "Configured AdGuardHome client", map[string]any{"success": true}) +} + +// DataSources defines the data sources implemented in the provider +func (p *adguardProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + NewClientDataSource, + } +} + +// Resources defines the resources implemented in the provider +func (p *adguardProvider) Resources(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + NewClientResource, + } +} diff --git a/adguard/provider_test.go b/adguard/provider_test.go new file mode 100644 index 0000000..ed85ec6 --- /dev/null +++ b/adguard/provider_test.go @@ -0,0 +1,32 @@ +package adguard + +import ( + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" +) + +const ( + // providerConfig is a shared configuration to combine with the actual + // test configuration so the AdGuard Home client is properly configured. + // It is also possible to use the ADGUARD_ environment variables instead, + // such as updating the Makefile and running the testing through that tool + providerConfig = ` +provider "adguard" { + // host = "localhost:8080" + // username = "admin" + // password = "SecretP@ssw0rd" + // scheme = "http" + // timeout = 5 +} +` +) + +var ( + // testAccProtoV6ProviderFactories are used to instantiate a provider during + // acceptance testing. The factory function will be invoked for every Terraform + // CLI command executed to create a provider server to which the CLI can + // reattach. + testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ + "adguard": providerserver.NewProtocol6WithError(New()), + } +) diff --git a/docker/conf/AdGuardHome.yaml b/docker/conf/AdGuardHome.yaml new file mode 100644 index 0000000..ae62d4d --- /dev/null +++ b/docker/conf/AdGuardHome.yaml @@ -0,0 +1,164 @@ +bind_host: 0.0.0.0 +bind_port: 8080 +users: + - name: admin + password: $2a$10$iQpJ7YlAHX7JBHOxHLAAieVRDKcBTfLoTAPmbUrCyetbLoy1YW1xy +auth_attempts: 5 +block_auth_min: 15 +http_proxy: "" +language: "" +theme: auto +debug_pprof: false +web_session_ttl: 720 +dns: + bind_hosts: + - 0.0.0.0 + port: 53 + anonymize_client_ip: false + protection_enabled: true + blocking_mode: default + blocking_ipv4: "" + blocking_ipv6: "" + blocked_response_ttl: 10 + parental_block_host: family-block.dns.adguard.com + safebrowsing_block_host: standard-block.dns.adguard.com + ratelimit: 20 + ratelimit_whitelist: [] + refuse_any: true + upstream_dns: + - https://dns10.quad9.net/dns-query + upstream_dns_file: "" + bootstrap_dns: + - 9.9.9.10 + - 149.112.112.10 + - 2620:fe::10 + - 2620:fe::fe:10 + all_servers: false + fastest_addr: false + fastest_timeout: 1s + allowed_clients: [] + disallowed_clients: [] + blocked_hosts: + - version.bind + - id.server + - hostname.bind + trusted_proxies: + - 127.0.0.0/8 + - ::1/128 + cache_size: 4194304 + cache_ttl_min: 0 + cache_ttl_max: 0 + cache_optimistic: false + bogus_nxdomain: [] + aaaa_disabled: false + enable_dnssec: false + edns_client_subnet: false + max_goroutines: 300 + handle_ddr: true + ipset: [] + ipset_file: "" + filtering_enabled: true + filters_update_interval: 24 + parental_enabled: false + safesearch_enabled: false + safebrowsing_enabled: false + safebrowsing_cache_size: 1048576 + safesearch_cache_size: 1048576 + parental_cache_size: 1048576 + cache_time: 30 + rewrites: [] + blocked_services: [] + upstream_timeout: 10s + private_networks: [] + use_private_ptr_resolvers: true + local_ptr_upstreams: [] + use_dns64: false + dns64_prefixes: [] + serve_http3: false + use_http3_upstreams: false +tls: + enabled: false + server_name: "" + force_https: false + port_https: 443 + port_dns_over_tls: 853 + port_dns_over_quic: 853 + port_dnscrypt: 0 + dnscrypt_config_file: "" + allow_unencrypted_doh: false + certificate_chain: "" + private_key: "" + certificate_path: "" + private_key_path: "" + strict_sni_check: false +querylog: + enabled: true + file_enabled: true + interval: 2160h + size_memory: 1000 + ignored: [] +statistics: + enabled: true + interval: 1 + ignored: [] +filters: + - enabled: true + url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt + name: AdGuard DNS filter + id: 1 + - enabled: false + url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt + name: AdAway Default Blocklist + id: 2 +whitelist_filters: [] +user_rules: [] +dhcp: + enabled: false + interface_name: "" + local_domain_name: lan + dhcpv4: + gateway_ip: "" + subnet_mask: "" + range_start: "" + range_end: "" + lease_duration: 86400 + icmp_timeout_msec: 1000 + options: [] + dhcpv6: + range_start: "" + lease_duration: 86400 + ra_slaac_only: false + ra_allow_slaac: false +clients: + runtime_sources: + whois: true + arp: true + rdns: true + dhcp: true + hosts: true + persistent: + - name: Test Client Data Source + tags: + - device_other + ids: + - 192.168.100.100 + blocked_services: [] + upstreams: [] + use_global_settings: true + filtering_enabled: false + parental_enabled: false + safesearch_enabled: false + safebrowsing_enabled: false + use_global_blocked_services: true +log_file: "" +log_max_backups: 0 +log_max_size: 100 +log_max_age: 3 +log_compress: false +log_localtime: false +verbose: false +os: + group: "" + user: "" + rlimit_nofile: 0 +schema_version: 16 diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml new file mode 100644 index 0000000..6a4f811 --- /dev/null +++ b/docker/docker-compose.yaml @@ -0,0 +1,11 @@ +version: "3" +services: + adguardhome: + image: adguard/adguardhome + container_name: adguardhome + restart: unless-stopped + volumes: + - "./conf:/opt/adguardhome/conf" + ports: + - "8080:8080/tcp" + - "3000:3000/tcp" diff --git a/docs/data-sources/client.md b/docs/data-sources/client.md new file mode 100644 index 0000000..7f50965 --- /dev/null +++ b/docs/data-sources/client.md @@ -0,0 +1,46 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "adguard_client Data Source - adguard" +subcategory: "" +description: |- + +--- + +# adguard_client (Data Source) + + + +## Example Usage + +```terraform +# get a client +data "adguard_client" "test" { + name = "Test Client Data Source" +} +``` + + +## Schema + +### Required + +- `name` (String) Name of the client + +### Optional + +- `blocked_services` (List of String) List of blocked services for this client +- `filtering_enabled` (Boolean) Whether to have filtering enabled on this client +- `ids` (List of String) List of identifiers for this client (IP, CIDR, MAC, or ClientID) +- `parental_enabled` (Boolean) Whether to have AdGuard parental controls enabled on this client +- `safebrowsing_enabled` (Boolean) Whether to have AdGuard browsing security enabled on this client +- `safesearch_enabled` (Boolean) Whether to enforce safe search on this client +- `tags` (List of String) List of tags for this client +- `upstreams` (List of String) List of upstream DNS server for this client +- `use_global_blocked_services` (Boolean) Whether to use global settings for blocked services +- `use_global_settings` (Boolean) Whether to use global settings on this client + +### Read-Only + +- `id` (String) Placeholder identifier attribute + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..f24782f --- /dev/null +++ b/docs/index.md @@ -0,0 +1,35 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "adguard Provider" +subcategory: "" +description: |- + +--- + +# adguard Provider + + + +## Example Usage + +```terraform +# configuration for the provider +provider "adguard" { + host = "localhost:8080" + username = "admin" + password = "SecretP@ssw0rd" + scheme = "http" # defaults to https + timeout = 5 # in seconds, defaults to 10 +} +``` + + +## Schema + +### Optional + +- `host` (String) The hostname of the AdGuard Home instance. Include the port if not on a standard HTTP/HTTPS port +- `password` (String, Sensitive) The password of the AdGuard Home instance +- `scheme` (String) The HTTP scheme of the AdGuard Home instance. Can be either `http` or `https` (default) +- `timeout` (Number) The timeout (in seconds) for making requests to AdGuard Home. Defaults to **10** +- `username` (String) The username of the AdGuard Home instance diff --git a/docs/resources/client.md b/docs/resources/client.md new file mode 100644 index 0000000..2302cd7 --- /dev/null +++ b/docs/resources/client.md @@ -0,0 +1,55 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "adguard_client Resource - adguard" +subcategory: "" +description: |- + +--- + +# adguard_client (Resource) + + + +## Example Usage + +```terraform +# manage a client +resource "adguard_client" "test" { + name = "Test Client" + ids = ["192.168.100.15", "test-client"] +} +``` + + +## Schema + +### Required + +- `ids` (List of String) List of identifiers for this client (IP, CIDR, MAC, or ClientID) +- `name` (String) Name of the client + +### Optional + +- `blocked_services` (List of String) List of blocked services for this client +- `filtering_enabled` (Boolean) Whether to have filtering enabled on this client +- `parental_enabled` (Boolean) Whether to have AdGuard parental controls enabled on this client +- `safebrowsing_enabled` (Boolean) Whether to have AdGuard browsing security enabled on this client +- `safesearch_enabled` (Boolean) Whether to enforce safe search on this client +- `tags` (List of String) List of tags for this client +- `upstreams` (List of String) List of upstream DNS server for this client +- `use_global_blocked_services` (Boolean) Whether to use global settings for blocked services +- `use_global_settings` (Boolean) Whether to use global settings on this client + +### Read-Only + +- `id` (String) Internal identifier for this client +- `last_updated` (String) Timestamp of the last Terraform update of the client + +## Import + +Import is supported using the following syntax: + +```shell +# Client can be imported by specifying the name +terraform import adguard_client.test "Test Client" +``` diff --git a/examples/data-sources/adguard_client/data-source.tf b/examples/data-sources/adguard_client/data-source.tf new file mode 100644 index 0000000..1706ada --- /dev/null +++ b/examples/data-sources/adguard_client/data-source.tf @@ -0,0 +1,4 @@ +# get a client +data "adguard_client" "test" { + name = "Test Client Data Source" +} diff --git a/examples/main.tf b/examples/main.tf new file mode 100644 index 0000000..9bcf171 --- /dev/null +++ b/examples/main.tf @@ -0,0 +1,25 @@ +terraform { + required_providers { + adguard = { + version = "0.1.0" + source = "gmichels/adguard" + } + } +} + +provider "adguard" { + host = "localhost:8080" + username = "admin" + password = "SecretP@ssw0rd" + scheme = "http" # defaults to https + timeout = 5 # in seconds, defaults to 10 +} + +data "adguard_client" "test" { + name = "Test Client Data Source" +} + +resource "adguard_client" "test" { + name = "Test Client" + ids = ["192.168.100.15", "test-client"] +} diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf new file mode 100644 index 0000000..56286da --- /dev/null +++ b/examples/provider/provider.tf @@ -0,0 +1,8 @@ +# configuration for the provider +provider "adguard" { + host = "localhost:8080" + username = "admin" + password = "SecretP@ssw0rd" + scheme = "http" # defaults to https + timeout = 5 # in seconds, defaults to 10 +} diff --git a/examples/resources/adguard_client/import.sh b/examples/resources/adguard_client/import.sh new file mode 100644 index 0000000..6d99f0a --- /dev/null +++ b/examples/resources/adguard_client/import.sh @@ -0,0 +1,2 @@ +# Client can be imported by specifying the name +terraform import adguard_client.test "Test Client" diff --git a/examples/resources/adguard_client/resource.tf b/examples/resources/adguard_client/resource.tf new file mode 100644 index 0000000..a19b8bc --- /dev/null +++ b/examples/resources/adguard_client/resource.tf @@ -0,0 +1,5 @@ +# manage a client +resource "adguard_client" "test" { + name = "Test Client" + ids = ["192.168.100.15", "test-client"] +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a976f8e --- /dev/null +++ b/go.mod @@ -0,0 +1,73 @@ +module github.com/gmichels/terraform-provider-adguard + +go 1.20 + +require ( + github.com/gmichels/adguard-client-go v0.1.0 + github.com/hashicorp/terraform-plugin-docs v0.14.0 + github.com/hashicorp/terraform-plugin-framework v1.1.1 + github.com/hashicorp/terraform-plugin-framework-validators v0.10.0 + github.com/hashicorp/terraform-plugin-go v0.14.3 + github.com/hashicorp/terraform-plugin-log v0.8.0 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0 + github.com/terraform-community-providers/terraform-plugin-framework-utils v0.3.0 +) + +require ( + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.1.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.2 // indirect + github.com/agext/levenshtein v1.2.2 // indirect + github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/errwrap v1.1.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.4.1-0.20200414143053-d3edf31b6320 // indirect + github.com/hashicorp/go-hclog v1.4.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/hc-install v0.5.0 // indirect + github.com/hashicorp/hcl/v2 v2.16.1 // indirect + github.com/hashicorp/logutils v1.0.0 // indirect + github.com/hashicorp/terraform-exec v0.18.0 // indirect + github.com/hashicorp/terraform-json v0.15.0 // indirect + github.com/hashicorp/terraform-registry-address v0.1.0 // indirect + github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect + github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mitchellh/cli v1.1.5 // 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.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/posener/complete v1.2.3 // indirect + github.com/russross/blackfriday v1.6.0 // indirect + github.com/shopspring/decimal v1.3.1 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect + github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect + github.com/vmihailenco/tagparser v0.1.2 // indirect + github.com/zclconf/go-cty v1.13.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/mod v0.7.0 // indirect + golang.org/x/net v0.6.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20200711021454-869866162049 // indirect + google.golang.org/grpc v1.51.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..43a6264 --- /dev/null +++ b/go.sum @@ -0,0 +1,369 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +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/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gmichels/adguard-client-go v0.1.0 h1:sgw3W+eT6uzGuVSQBGWoMKhmD6YUdsxIqnDLePXLh1Q= +github.com/gmichels/adguard-client-go v0.1.0/go.mod h1:77E8dDI1mhRP5E7tNJWvtF2PLqZiqwcmMrgBUCCc4KY= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.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.1/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.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= +github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= +github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I= +github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +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.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= +github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +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.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hc-install v0.5.0 h1:D9bl4KayIYKEeJ4vUDe9L5huqxZXczKaykSRcmQ0xY0= +github.com/hashicorp/hc-install v0.5.0/go.mod h1:JyzMfbzfSBSjoDCRPna1vi/24BEDxFaCPfdHtM5SCdo= +github.com/hashicorp/hcl/v2 v2.16.1 h1:BwuxEMD/tsYgbhIW7UuI3crjovf3MzuFWiVgiv57iHg= +github.com/hashicorp/hcl/v2 v2.16.1/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng= +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.18.0 h1:BJa6/Fhxnb0zvsEGqUrFSybcnhAiBVSUgG7s09b6XlI= +github.com/hashicorp/terraform-exec v0.18.0/go.mod h1:6PMRgg0Capig5Fn0zW9/+WM3vQsdwotwa8uxDVzLpHE= +github.com/hashicorp/terraform-json v0.15.0 h1:/gIyNtR6SFw6h5yzlbDbACyGvIhKtQi8mTsbkNd79lE= +github.com/hashicorp/terraform-json v0.15.0/go.mod h1:+L1RNzjDU5leLFZkHTFTbJXaoqUC6TqXlFgDoOXrtvk= +github.com/hashicorp/terraform-plugin-docs v0.14.0 h1:arfzRQvJAsIayBEQjkMSfiX2FBgfeLGxyq8lJegn6rA= +github.com/hashicorp/terraform-plugin-docs v0.14.0/go.mod h1:RD0Ckw2HNoLr47tlUWVJpHWHHLNQevfTet8ckB9TZ7c= +github.com/hashicorp/terraform-plugin-framework v1.1.1 h1:PbnEKHsIU8KTTzoztHQGgjZUWx7Kk8uGtpGMMc1p+oI= +github.com/hashicorp/terraform-plugin-framework v1.1.1/go.mod h1:DyZPxQA+4OKK5ELxFIIcqggcszqdWWUpTLPHAhS/tkY= +github.com/hashicorp/terraform-plugin-framework-validators v0.10.0 h1:4L0tmy/8esP6OcvocVymw52lY0HyQ5OxB7VNl7k4bS0= +github.com/hashicorp/terraform-plugin-framework-validators v0.10.0/go.mod h1:qdQJCdimB9JeX2YwOpItEu+IrfoJjWQ5PhLpAOMDQAE= +github.com/hashicorp/terraform-plugin-go v0.14.3 h1:nlnJ1GXKdMwsC8g1Nh05tK2wsC3+3BL/DBBxFEki+j0= +github.com/hashicorp/terraform-plugin-go v0.14.3/go.mod h1:7ees7DMZ263q8wQ6E4RdIdR6nHHJtrdt4ogX5lPkX1A= +github.com/hashicorp/terraform-plugin-log v0.8.0 h1:pX2VQ/TGKu+UU1rCay0OlzosNKe4Nz1pepLXj95oyy0= +github.com/hashicorp/terraform-plugin-log v0.8.0/go.mod h1:1myFrhVsBLeylQzYYEV17VVjtG8oYPRFdaZs7xdW2xs= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0 h1:iNRjaJCatQS1rIbHs/vDvJ0GECsaGgxx780chA2Irpk= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0/go.mod h1:XnVNLIS6bdMJbjSDujhX4Rlk24QpbGKbnrVFM4tZ7OU= +github.com/hashicorp/terraform-registry-address v0.1.0 h1:W6JkV9wbum+m516rCl5/NjKxCyTVaaUBbzYcMzBDO3U= +github.com/hashicorp/terraform-registry-address v0.1.0/go.mod h1:EnyO2jYO6j29DTHbJcm00E5nQTFeTtyZH3H5ycydQ5A= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +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/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +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 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= +github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +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-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +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.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +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.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= +github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/terraform-community-providers/terraform-plugin-framework-utils v0.3.0 h1:9p3a6Y9H/RiBpeY+V28R3nSPLAOG8z4lP17QyunXMfE= +github.com/terraform-community-providers/terraform-plugin-framework-utils v0.3.0/go.mod h1:qxBCEJqhF0NPLX+FrRYALlpxXSi1nhTx/x1aimUEqRY= +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/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U= +github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= +github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= +github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0= +github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/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.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +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/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= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200711021454-869866162049 h1:YFTFpQhgvrLrmxtiIncJxFXeCyq84ixuKWVCaCAi9Oc= +google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/main.go b/main.go new file mode 100644 index 0000000..a08f6c9 --- /dev/null +++ b/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "context" + + "github.com/gmichels/terraform-provider-adguard/adguard" + "github.com/hashicorp/terraform-plugin-framework/providerserver" +) + +// provider documentation generation +//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate --provider-name adguard + +func main() { + providerserver.Serve(context.Background(), adguard.New, providerserver.ServeOpts{ + Address: "registry.terraform.io/gmichels/adguard", + }) +} diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json new file mode 100644 index 0000000..295001a --- /dev/null +++ b/terraform-registry-manifest.json @@ -0,0 +1,6 @@ +{ + "version": 1, + "metadata": { + "protocol_versions": ["6.0"] + } +} diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..a82de6b --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,8 @@ +//go:build tools + +package tools + +import ( + // Ensure documentation generator is not removed from go.mod. + _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" +)