mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-30 02:31:10 +00:00
feat(acme): implement resources and data sources for ACME accounts (#1455)
* feat(acme): implement CRUD API for proxmox cluster ACME * feat(acme): implement acme_accounts data source * feat(acme): implement acme_account data source * fix(acme): wait for task status on account creation * feat(acme): implement account resource creation * feat(acme): implement account read * fix(acme): wait for task status on account update * feat(acme): implement account update * fix(acme): wait for task status on account deletion * feat(acme): implement account deletion * feat(acme): implement account import * feat(acme): provide correctly typed API response for `account` field * feat(acme): implement account schema for acme_account data source * fix(acme): read `location` into state in acme_account resource * fix(acme): ensure `name` of acme_account resource can't be changed * docs(acme): generate documentation * feat(acme): read back ACME account details from API * Revert "fix(acme): ensure `name` of acme_account resource can't be changed" * fix(acme): provide default for acme account name * fix(acme): acme account name can't be changed * chore(acme): update resource doc to clarify PVE auth requirements * chore(acme): add `created_at` attr to the resource, sort model fields & schema attributes alphabetically --------- Signed-off-by: Björn Brauer <zaubernerd@zaubernerd.de> Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com> Co-authored-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
parent
b589083a1a
commit
9de4037a82
52
docs/data-sources/virtual_environment_acme_account.md
Normal file
52
docs/data-sources/virtual_environment_acme_account.md
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
layout: page
|
||||
title: proxmox_virtual_environment_acme_account
|
||||
parent: Data Sources
|
||||
subcategory: Virtual Environment
|
||||
description: |-
|
||||
Retrieves information about a specific ACME account.
|
||||
---
|
||||
|
||||
# Data Source: proxmox_virtual_environment_acme_account
|
||||
|
||||
Retrieves information about a specific ACME account.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
// This will fetch all ACME accounts...
|
||||
data "proxmox_virtual_environment_acme_accounts" "all" {}
|
||||
|
||||
// ...which we will go through in order to fetch the whole data on each account.
|
||||
data "proxmox_virtual_environment_acme_account" "example" {
|
||||
for_each = data.proxmox_virtual_environment_acme_accounts.all.accounts
|
||||
name = each.value
|
||||
}
|
||||
|
||||
output "data_proxmox_virtual_environment_acme_account" {
|
||||
value = data.proxmox_virtual_environment_acme_account.example
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Optional
|
||||
|
||||
- `name` (String) The identifier of the ACME account to read.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `account` (Attributes) The ACME account information. (see [below for nested schema](#nestedatt--account))
|
||||
- `directory` (String) The directory URL of the ACME account.
|
||||
- `location` (String) The location URL of the ACME account.
|
||||
- `tos` (String) The URL of the terms of service of the ACME account.
|
||||
|
||||
<a id="nestedatt--account"></a>
|
||||
### Nested Schema for `account`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `contact` (List of String) An array of contact email addresses.
|
||||
- `created_at` (String) The timestamp of the account creation.
|
||||
- `status` (String) The status of the account. Can be one of `valid`, `deactivated` or `revoked`.
|
29
docs/data-sources/virtual_environment_acme_accounts.md
Normal file
29
docs/data-sources/virtual_environment_acme_accounts.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
layout: page
|
||||
title: proxmox_virtual_environment_acme_accounts
|
||||
parent: Data Sources
|
||||
subcategory: Virtual Environment
|
||||
description: |-
|
||||
Retrieves the list of ACME accounts.
|
||||
---
|
||||
|
||||
# Data Source: proxmox_virtual_environment_acme_accounts
|
||||
|
||||
Retrieves the list of ACME accounts.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "proxmox_virtual_environment_acme_accounts" "example" {}
|
||||
|
||||
output "data_proxmox_virtual_environment_acme_accounts" {
|
||||
value = data.proxmox_virtual_environment_acme_accounts.example.accounts
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `accounts` (Set of String) The identifiers of the ACME accounts.
|
@ -320,7 +320,10 @@ provider "proxmox" {
|
||||
-> The token authentication is taking precedence over the password authentication.
|
||||
|
||||
-> Not all Proxmox API operations are supported via API Token.
|
||||
You may see errors like `error creating container: received an HTTP 403 response - Reason: Permission check failed (changing feature flags for privileged container is only allowed for root@pam)` or `error creating VM: received an HTTP 500 response - Reason: only root can set 'arch' config` when using API Token authentication, even when `Administrator` role or the `root@pam` user is used with the token.
|
||||
You may see errors like
|
||||
`error creating container: received an HTTP 403 response - Reason: Permission check failed (changing feature flags for privileged container is only allowed for root@pam)` or
|
||||
`error creating VM: received an HTTP 500 response - Reason: only root can set 'arch' config` or
|
||||
`Permission check failed (user != root@pam)` when using API Token authentication, even when `Administrator` role or the `root@pam` user is used with the token.
|
||||
The workaround is to use password authentication for those operations.
|
||||
|
||||
-> You can also configure additional Proxmox users and roles using [`virtual_environment_user`](https://registry.terraform.io/providers/bpg/proxmox/latest/docs/data-sources/virtual_environment_user) and [`virtual_environment_role`](https://registry.terraform.io/providers/bpg/proxmox/latest/docs/data-sources/virtual_environment_role) resources of the provider.
|
||||
|
56
docs/resources/virtual_environment_acme_account.md
Normal file
56
docs/resources/virtual_environment_acme_account.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
layout: page
|
||||
title: proxmox_virtual_environment_acme_account
|
||||
parent: Resources
|
||||
subcategory: Virtual Environment
|
||||
description: |-
|
||||
Manages an ACME account in a Proxmox VE cluster.
|
||||
~> This resource requires root@pam authentication.
|
||||
---
|
||||
|
||||
# Resource: proxmox_virtual_environment_acme_account
|
||||
|
||||
Manages an ACME account in a Proxmox VE cluster.
|
||||
|
||||
~> This resource requires `root@pam` authentication.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "proxmox_virtual_environment_acme_account" "example" {
|
||||
name = "example"
|
||||
contact = "example@email.com"
|
||||
directory = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
tos = "https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- `contact` (String) The contact email addresses.
|
||||
|
||||
### Optional
|
||||
|
||||
- `directory` (String) The URL of the ACME CA directory endpoint.
|
||||
- `eab_hmac_key` (String) The HMAC key for External Account Binding.
|
||||
- `eab_kid` (String) The Key Identifier for External Account Binding.
|
||||
- `name` (String) The ACME account config file name.
|
||||
- `tos` (String) The URL of CA TermsOfService - setting this indicates agreement.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `created_at` (String) The timestamp of the ACME account creation.
|
||||
- `location` (String) The location of the ACME account.
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env sh
|
||||
# ACME accounts can be imported using their name, e.g.:
|
||||
terraform import proxmox_virtual_environment_acme_account.example example
|
||||
```
|
@ -0,0 +1,12 @@
|
||||
// This will fetch all ACME accounts...
|
||||
data "proxmox_virtual_environment_acme_accounts" "all" {}
|
||||
|
||||
// ...which we will go through in order to fetch the whole data on each account.
|
||||
data "proxmox_virtual_environment_acme_account" "example" {
|
||||
for_each = data.proxmox_virtual_environment_acme_accounts.all.accounts
|
||||
name = each.value
|
||||
}
|
||||
|
||||
output "data_proxmox_virtual_environment_acme_account" {
|
||||
value = data.proxmox_virtual_environment_acme_account.example
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
data "proxmox_virtual_environment_acme_accounts" "example" {}
|
||||
|
||||
output "data_proxmox_virtual_environment_acme_accounts" {
|
||||
value = data.proxmox_virtual_environment_acme_accounts.example.accounts
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env sh
|
||||
# ACME accounts can be imported using their name, e.g.:
|
||||
terraform import proxmox_virtual_environment_acme_account.example example
|
@ -0,0 +1,6 @@
|
||||
resource "proxmox_virtual_environment_acme_account" "example" {
|
||||
name = "example"
|
||||
contact = "example@email.com"
|
||||
directory = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
tos = "https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf"
|
||||
}
|
191
fwprovider/acme/datasource_acme_account.go
Normal file
191
fwprovider/acme/datasource_acme_account.go
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package acme
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/account"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
var (
|
||||
_ datasource.DataSource = &acmeAccountDatasource{}
|
||||
_ datasource.DataSourceWithConfigure = &acmeAccountDatasource{}
|
||||
)
|
||||
|
||||
// NewACMEAccountDataSource is a helper function to simplify the provider implementation.
|
||||
func NewACMEAccountDataSource() datasource.DataSource {
|
||||
return &acmeAccountDatasource{}
|
||||
}
|
||||
|
||||
// acmeAccountDatasource is the data source implementation for ACME accounts.
|
||||
type acmeAccountDatasource struct {
|
||||
client *account.Client
|
||||
}
|
||||
|
||||
type accountDataModel struct {
|
||||
Contact []types.String `tfsdk:"contact"`
|
||||
CreatedAt types.String `tfsdk:"created_at"`
|
||||
Status types.String `tfsdk:"status"`
|
||||
}
|
||||
|
||||
func (m *accountDataModel) attrTypes() map[string]attr.Type {
|
||||
return map[string]attr.Type{
|
||||
"contact": types.ListType{ElemType: types.StringType},
|
||||
"created_at": types.StringType,
|
||||
"status": types.StringType,
|
||||
}
|
||||
}
|
||||
|
||||
// accountModel is the model used to represent an ACME account.
|
||||
type accountModel struct {
|
||||
// Name is the ACME account config file name.
|
||||
Name types.String `tfsdk:"name"`
|
||||
// Account is the ACME account information.
|
||||
Account types.Object `tfsdk:"account"`
|
||||
// Directory is the URL of the ACME CA directory endpoint.
|
||||
Directory types.String `tfsdk:"directory"`
|
||||
// Location is the location of the ACME account.
|
||||
Location types.String `tfsdk:"location"`
|
||||
// URL of CA TermsOfService - setting this indicates agreement.
|
||||
TOS types.String `tfsdk:"tos"`
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
func (d *acmeAccountDatasource) Metadata(
|
||||
_ context.Context,
|
||||
req datasource.MetadataRequest,
|
||||
resp *datasource.MetadataResponse,
|
||||
) {
|
||||
resp.TypeName = req.ProviderTypeName + "_acme_account"
|
||||
}
|
||||
|
||||
// Schema returns the schema for the data source.
|
||||
func (d *acmeAccountDatasource) Schema(
|
||||
_ context.Context,
|
||||
_ datasource.SchemaRequest,
|
||||
resp *datasource.SchemaResponse,
|
||||
) {
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Retrieves information about a specific ACME account.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"name": schema.StringAttribute{
|
||||
Description: "The identifier of the ACME account to read.",
|
||||
Optional: true,
|
||||
},
|
||||
"account": schema.SingleNestedAttribute{
|
||||
Description: "The ACME account information.",
|
||||
Computed: true,
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"contact": schema.ListAttribute{
|
||||
Description: "An array of contact email addresses.",
|
||||
ElementType: types.StringType,
|
||||
Computed: true,
|
||||
},
|
||||
"created_at": schema.StringAttribute{
|
||||
Description: "The timestamp of the account creation.",
|
||||
Computed: true,
|
||||
},
|
||||
"status": schema.StringAttribute{
|
||||
Description: "The status of the account.",
|
||||
MarkdownDescription: "The status of the account. Can be one of `valid`, `deactivated` or `revoked`.",
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"directory": schema.StringAttribute{
|
||||
Description: "The directory URL of the ACME account.",
|
||||
Computed: true,
|
||||
},
|
||||
"location": schema.StringAttribute{
|
||||
Description: "The location URL of the ACME account.",
|
||||
Computed: true,
|
||||
},
|
||||
"tos": schema.StringAttribute{
|
||||
Description: "The URL of the terms of service of the ACME account.",
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Configure adds the provider-configured client to the data source.
|
||||
func (d *acmeAccountDatasource) Configure(
|
||||
_ context.Context,
|
||||
req datasource.ConfigureRequest,
|
||||
resp *datasource.ConfigureResponse,
|
||||
) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().ACME().Account()
|
||||
}
|
||||
|
||||
// Read retrieves the ACME account information.
|
||||
func (d *acmeAccountDatasource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var state accountModel
|
||||
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
name := state.Name.ValueString()
|
||||
|
||||
account, err := d.client.Get(ctx, name)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Unable to read ACME account '%s'", name),
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
contactList := make([]types.String, len(account.Account.Contact))
|
||||
for i, contact := range account.Account.Contact {
|
||||
contactList[i] = types.StringValue(contact)
|
||||
}
|
||||
|
||||
data := &accountDataModel{
|
||||
Contact: contactList,
|
||||
CreatedAt: types.StringValue(account.Account.CreatedAt),
|
||||
Status: types.StringValue(account.Account.Status),
|
||||
}
|
||||
|
||||
accountObject, diags := types.ObjectValueFrom(ctx, data.attrTypes(), data)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
state.Account = accountObject
|
||||
|
||||
state.Directory = types.StringValue(account.Directory)
|
||||
state.Location = types.StringValue(account.Location)
|
||||
state.TOS = types.StringValue(account.TOS)
|
||||
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
||||
}
|
119
fwprovider/acme/datasource_acme_accounts.go
Normal file
119
fwprovider/acme/datasource_acme_accounts.go
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package acme
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/account"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
var (
|
||||
_ datasource.DataSource = &acmeAccountsDatasource{}
|
||||
_ datasource.DataSourceWithConfigure = &acmeAccountsDatasource{}
|
||||
)
|
||||
|
||||
// NewACMEAccountsDataSource is a helper function to simplify the provider implementation.
|
||||
func NewACMEAccountsDataSource() datasource.DataSource {
|
||||
return &acmeAccountsDatasource{}
|
||||
}
|
||||
|
||||
// acmeAccountsDatasource is the data source implementation for ACME accounts.
|
||||
type acmeAccountsDatasource struct {
|
||||
client *account.Client
|
||||
}
|
||||
|
||||
// acmeAccountsModel maps the schema data for the ACME accounts data source.
|
||||
type acmeAccountsModel struct {
|
||||
Accounts types.Set `tfsdk:"accounts"`
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
func (d *acmeAccountsDatasource) Metadata(
|
||||
_ context.Context,
|
||||
req datasource.MetadataRequest,
|
||||
resp *datasource.MetadataResponse,
|
||||
) {
|
||||
resp.TypeName = req.ProviderTypeName + "_acme_accounts"
|
||||
}
|
||||
|
||||
// Schema returns the schema for the data source.
|
||||
func (d *acmeAccountsDatasource) Schema(
|
||||
_ context.Context,
|
||||
_ datasource.SchemaRequest,
|
||||
resp *datasource.SchemaResponse,
|
||||
) {
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Retrieves the list of ACME accounts.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"accounts": schema.SetAttribute{
|
||||
Description: "The identifiers of the ACME accounts.",
|
||||
ElementType: types.StringType,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Configure adds the provider-configured client to the data source.
|
||||
func (d *acmeAccountsDatasource) Configure(
|
||||
_ context.Context,
|
||||
req datasource.ConfigureRequest,
|
||||
resp *datasource.ConfigureResponse,
|
||||
) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().ACME().Account()
|
||||
}
|
||||
|
||||
// Read fetches the list of ACME Accounts from the Proxmox cluster then converts it to a list of strings.
|
||||
func (d *acmeAccountsDatasource) Read(ctx context.Context, _ datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var state acmeAccountsModel
|
||||
|
||||
list, err := d.client.List(ctx)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unable to read ACME accounts",
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
accounts := make([]attr.Value, len(list))
|
||||
for i, v := range list {
|
||||
accounts[i] = types.StringValue(v.Name)
|
||||
}
|
||||
|
||||
accountsValue, diags := types.SetValue(types.StringType, accounts)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
state.Accounts = accountsValue
|
||||
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
||||
}
|
319
fwprovider/acme/resource_acme_account.go
Normal file
319
fwprovider/acme/resource_acme_account.go
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package acme
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"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/stringdefault"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/account"
|
||||
)
|
||||
|
||||
var (
|
||||
_ resource.Resource = &acmeAccountResource{}
|
||||
_ resource.ResourceWithConfigure = &acmeAccountResource{}
|
||||
_ resource.ResourceWithImportState = &acmeAccountResource{}
|
||||
)
|
||||
|
||||
// NewACMEAccountResource creates a new resource for managing ACME accounts.
|
||||
func NewACMEAccountResource() resource.Resource {
|
||||
return &acmeAccountResource{}
|
||||
}
|
||||
|
||||
// acmeAccountResource contains the resource's internal data.
|
||||
type acmeAccountResource struct {
|
||||
// The ACME account API client
|
||||
client account.Client
|
||||
}
|
||||
|
||||
// acmeAccountModel maps the schema data for the ACME account resource.
|
||||
type acmeAccountModel struct {
|
||||
// Contact email addresses.
|
||||
Contact types.String `tfsdk:"contact"`
|
||||
// CreatedAt timestamp of the account creation.
|
||||
CreatedAt types.String `tfsdk:"created_at"`
|
||||
// URL of ACME CA directory endpoint.
|
||||
Directory types.String `tfsdk:"directory"`
|
||||
// HMAC key for External Account Binding.
|
||||
EABHMACKey types.String `tfsdk:"eab_hmac_key"`
|
||||
// Key Identifier for External Account Binding.
|
||||
EABKID types.String `tfsdk:"eab_kid"`
|
||||
// Location of the ACME account.
|
||||
Location types.String `tfsdk:"location"`
|
||||
// ACME account config file name.
|
||||
Name types.String `tfsdk:"name"`
|
||||
// URL of CA TermsOfService - setting this indicates agreement.
|
||||
TOS types.String `tfsdk:"tos"`
|
||||
}
|
||||
|
||||
// Metadata defines the name of the resource.
|
||||
func (r *acmeAccountResource) Metadata(
|
||||
_ context.Context,
|
||||
req resource.MetadataRequest,
|
||||
resp *resource.MetadataResponse,
|
||||
) {
|
||||
resp.TypeName = req.ProviderTypeName + "_acme_account"
|
||||
}
|
||||
|
||||
// Schema defines the schema for the resource.
|
||||
func (r *acmeAccountResource) Schema(
|
||||
_ context.Context,
|
||||
_ resource.SchemaRequest,
|
||||
resp *resource.SchemaResponse,
|
||||
) {
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Manages an ACME account in a Proxmox VE cluster.",
|
||||
MarkdownDescription: "Manages an ACME account in a Proxmox VE cluster.\n\n" +
|
||||
"~> This resource requires `root@pam` authentication.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"contact": schema.StringAttribute{
|
||||
Description: "The contact email addresses.",
|
||||
Required: true,
|
||||
},
|
||||
"created_at": schema.StringAttribute{
|
||||
Description: "The timestamp of the ACME account creation.",
|
||||
Computed: true,
|
||||
},
|
||||
"directory": schema.StringAttribute{
|
||||
Description: "The URL of the ACME CA directory endpoint.",
|
||||
Validators: []validator.String{
|
||||
stringvalidator.RegexMatches(
|
||||
regexp.MustCompile(`^https?://.*$`),
|
||||
"must be a valid URL",
|
||||
),
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
"eab_hmac_key": schema.StringAttribute{
|
||||
Description: "The HMAC key for External Account Binding.",
|
||||
Optional: true,
|
||||
},
|
||||
"eab_kid": schema.StringAttribute{
|
||||
Description: "The Key Identifier for External Account Binding.",
|
||||
Optional: true,
|
||||
},
|
||||
"location": schema.StringAttribute{
|
||||
Description: "The location of the ACME account.",
|
||||
Computed: true,
|
||||
},
|
||||
"name": schema.StringAttribute{
|
||||
Description: "The ACME account config file name.",
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Default: stringdefault.StaticString("default"),
|
||||
},
|
||||
"tos": schema.StringAttribute{
|
||||
Description: "The URL of CA TermsOfService - setting this indicates agreement.",
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Configure accesses the provider-configured Proxmox API client on behalf of the resource.
|
||||
func (r *acmeAccountResource) Configure(
|
||||
_ context.Context,
|
||||
req resource.ConfigureRequest,
|
||||
resp *resource.ConfigureResponse,
|
||||
) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if ok {
|
||||
r.client = *client.Cluster().ACME().Account()
|
||||
} else {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new ACME account on the Proxmox cluster.
|
||||
func (r *acmeAccountResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
||||
var plan acmeAccountModel
|
||||
|
||||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
createRequest := &account.ACMEAccountCreateRequestBody{}
|
||||
createRequest.Contact = plan.Contact.ValueString()
|
||||
createRequest.Directory = plan.Directory.ValueString()
|
||||
createRequest.EABHMACKey = plan.EABHMACKey.ValueString()
|
||||
createRequest.EABKID = plan.EABKID.ValueString()
|
||||
createRequest.Name = plan.Name.ValueString()
|
||||
createRequest.TOS = plan.TOS.ValueString()
|
||||
|
||||
err := r.client.Create(ctx, createRequest)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "already exists") {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Unable to create ACME account '%s'", plan.Name),
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("ACME account '%s' already exists", plan.Name),
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
|
||||
r.readBack(ctx, &plan, &resp.Diagnostics, &resp.State)
|
||||
}
|
||||
|
||||
// Read retrieves the current state of the ACME account from the Proxmox cluster.
|
||||
func (r *acmeAccountResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
|
||||
var state acmeAccountModel
|
||||
|
||||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
found, diags := r.read(ctx, &state)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
if !resp.Diagnostics.HasError() {
|
||||
if found {
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
|
||||
} else {
|
||||
resp.State.RemoveResource(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update modifies an existing ACME account on the Proxmox cluster.
|
||||
func (r *acmeAccountResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
|
||||
var plan acmeAccountModel
|
||||
|
||||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
updateRequest := &account.ACMEAccountUpdateRequestBody{}
|
||||
updateRequest.Contact = plan.Contact.ValueString()
|
||||
|
||||
err := r.client.Update(ctx, plan.Name.ValueString(), updateRequest)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Unable to update ACME account '%s'", plan.Name),
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.readBack(ctx, &plan, &resp.Diagnostics, &resp.State)
|
||||
}
|
||||
|
||||
// Delete removes an existing ACME account from the Proxmox cluster.
|
||||
func (r *acmeAccountResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
|
||||
var state acmeAccountModel
|
||||
|
||||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
err := r.client.Delete(ctx, state.Name.ValueString())
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Unable to delete ACME account '%s'", state.Name),
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// ImportState retrieves the current state of an existing ACME account from the Proxmox cluster.
|
||||
func (r *acmeAccountResource) ImportState(
|
||||
ctx context.Context,
|
||||
req resource.ImportStateRequest,
|
||||
resp *resource.ImportStateResponse,
|
||||
) {
|
||||
resource.ImportStatePassthroughID(ctx, path.Root("name"), req, resp)
|
||||
}
|
||||
|
||||
func (r *acmeAccountResource) readBack(
|
||||
ctx context.Context,
|
||||
data *acmeAccountModel,
|
||||
respDiags *diag.Diagnostics,
|
||||
respState *tfsdk.State,
|
||||
) {
|
||||
found, diags := r.read(ctx, data)
|
||||
|
||||
respDiags.Append(diags...)
|
||||
|
||||
if !found {
|
||||
respDiags.AddError(
|
||||
fmt.Sprintf("ACME account '%s' not found after update", data.Name),
|
||||
"Failed to find ACME account when trying to read back the updated ACME account's data.",
|
||||
)
|
||||
}
|
||||
|
||||
if !respDiags.HasError() {
|
||||
respDiags.Append(respState.Set(ctx, data)...)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *acmeAccountResource) read(ctx context.Context, data *acmeAccountModel) (bool, diag.Diagnostics) {
|
||||
name := data.Name.ValueString()
|
||||
|
||||
acc, err := r.client.Get(ctx, name)
|
||||
if err != nil {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
if !strings.Contains(err.Error(), "does not exist") {
|
||||
diags.AddError(
|
||||
fmt.Sprintf("Unable to read ACME account '%s'", name),
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
|
||||
return false, diags
|
||||
}
|
||||
|
||||
var contact string
|
||||
if len(acc.Account.Contact) > 0 {
|
||||
contact = strings.Replace(acc.Account.Contact[0], "mailto:", "", 1)
|
||||
}
|
||||
|
||||
data.Directory = types.StringValue(acc.Directory)
|
||||
data.TOS = types.StringValue(acc.TOS)
|
||||
data.Location = types.StringValue(acc.Location)
|
||||
data.Contact = types.StringValue(contact)
|
||||
data.CreatedAt = types.StringValue(acc.Account.CreatedAt)
|
||||
|
||||
return true, nil
|
||||
}
|
@ -26,6 +26,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/access"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/acme"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/ha"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/hardwaremapping"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/network"
|
||||
@ -444,6 +445,7 @@ func (p *proxmoxProvider) Resources(_ context.Context) []func() resource.Resourc
|
||||
return []func() resource.Resource{
|
||||
NewClusterOptionsResource,
|
||||
NewDownloadFileResource,
|
||||
acme.NewACMEAccountResource,
|
||||
apt.NewResourceRepo,
|
||||
apt.NewResourceStandardRepo,
|
||||
access.NewACLResource,
|
||||
@ -461,6 +463,8 @@ func (p *proxmoxProvider) Resources(_ context.Context) []func() resource.Resourc
|
||||
func (p *proxmoxProvider) DataSources(_ context.Context) []func() datasource.DataSource {
|
||||
return []func() datasource.DataSource{
|
||||
NewVersionDataSource,
|
||||
acme.NewACMEAccountsDataSource,
|
||||
acme.NewACMEAccountDataSource,
|
||||
apt.NewDataSourceRepo,
|
||||
apt.NewDataSourceStandardRepo,
|
||||
ha.NewHAGroupDataSource,
|
||||
|
125
proxmox/cluster/acme/account/acme_account.go
Normal file
125
proxmox/cluster/acme/account/acme_account.go
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package account
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
)
|
||||
|
||||
// List returns a list of ACME accounts.
|
||||
func (c *Client) List(ctx context.Context) ([]*ACMEAccountListResponseData, error) {
|
||||
resBody := &ACMEAccountListResponseBody{}
|
||||
|
||||
err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath(""), nil, resBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing ACME accounts: %w", err)
|
||||
}
|
||||
|
||||
if resBody.Data == nil {
|
||||
return nil, api.ErrNoDataObjectInResponse
|
||||
}
|
||||
|
||||
sort.Slice(resBody.Data, func(i, j int) bool {
|
||||
return resBody.Data[i].Name < resBody.Data[j].Name
|
||||
})
|
||||
|
||||
return resBody.Data, nil
|
||||
}
|
||||
|
||||
// Get retrieves a single ACME account based on its identifier.
|
||||
func (c *Client) Get(ctx context.Context, name string) (*ACMEAccountGetResponseData, error) {
|
||||
resBody := &ACMEAccountGetResponseBody{}
|
||||
|
||||
err := c.DoRequest(ctx, http.MethodGet, c.ExpandPath(url.PathEscape(name)), nil, resBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading ACME account: %w", err)
|
||||
}
|
||||
|
||||
if resBody.Data == nil {
|
||||
return nil, api.ErrNoDataObjectInResponse
|
||||
}
|
||||
|
||||
return resBody.Data, nil
|
||||
}
|
||||
|
||||
// Create creates a new ACME account.
|
||||
func (c *Client) Create(ctx context.Context, data *ACMEAccountCreateRequestBody) error {
|
||||
resBody := &ACMEAccountCreateResponseBody{}
|
||||
|
||||
err := c.DoRequest(ctx, http.MethodPost, c.ExpandPath(""), data, resBody)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating ACME account: %w", err)
|
||||
}
|
||||
|
||||
if resBody.Data == nil {
|
||||
return api.ErrNoDataObjectInResponse
|
||||
}
|
||||
|
||||
err = c.Tasks().WaitForTask(ctx, *resBody.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"error updating ACME account: failed waiting for task: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update updates an existing ACME account.
|
||||
func (c *Client) Update(ctx context.Context, accountName string, data *ACMEAccountUpdateRequestBody) error {
|
||||
resBody := &ACMEAccountUpdateResponseBody{}
|
||||
|
||||
err := c.DoRequest(ctx, http.MethodPut, c.ExpandPath(url.PathEscape(accountName)), data, resBody)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating ACME account: %w", err)
|
||||
}
|
||||
|
||||
if resBody.Data == nil {
|
||||
return api.ErrNoDataObjectInResponse
|
||||
}
|
||||
|
||||
err = c.Tasks().WaitForTask(ctx, *resBody.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"error updating ACME account: failed waiting for task: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes an ACME account.
|
||||
func (c *Client) Delete(ctx context.Context, accountName string) error {
|
||||
resBody := &ACMEAccountDeleteResponseBody{}
|
||||
|
||||
err := c.DoRequest(ctx, http.MethodDelete, c.ExpandPath(url.PathEscape(accountName)), nil, resBody)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting ACME account: %w", err)
|
||||
}
|
||||
|
||||
if resBody.Data == nil {
|
||||
return api.ErrNoDataObjectInResponse
|
||||
}
|
||||
|
||||
err = c.Tasks().WaitForTask(ctx, *resBody.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"error deleting ACME account: failed waiting for task: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
83
proxmox/cluster/acme/account/acme_account_types.go
Normal file
83
proxmox/cluster/acme/account/acme_account_types.go
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package account
|
||||
|
||||
// ACMEAccountListResponseBody contains the body from a ACME account list response.
|
||||
type ACMEAccountListResponseBody struct {
|
||||
Data []*ACMEAccountListResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// ACMEAccountListResponseData contains the data from a ACME account list response.
|
||||
type ACMEAccountListResponseData struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// ACMEAccountGetResponseBody contains the body from a ACME account get response.
|
||||
type ACMEAccountGetResponseBody struct {
|
||||
Data *ACMEAccountGetResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// ACMEAccountData contains the data from a ACME account.
|
||||
type ACMEAccountData struct {
|
||||
// An array of contact email addresses.
|
||||
Contact []string `json:"contact"`
|
||||
// Timestamp of the account creation.
|
||||
CreatedAt string `json:"createdAt"`
|
||||
// Status of the account. Can be one of "valid", "deactivated" or "revoked".
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// ACMEAccountGetResponseData contains the data from a ACME account get response.
|
||||
type ACMEAccountGetResponseData struct {
|
||||
// Account is the ACME account data.
|
||||
Account ACMEAccountData `json:"account"`
|
||||
// Directory is the URL of the ACME CA directory endpoint.
|
||||
Directory string `json:"directory"`
|
||||
// Location is the location of the ACME account.
|
||||
Location string `json:"location"`
|
||||
// TOS is the terms of service URL.
|
||||
TOS string `json:"tos"`
|
||||
}
|
||||
|
||||
// ACMEAccountCreateRequestBody contains the body for creating a new ACME account.
|
||||
type ACMEAccountCreateRequestBody struct {
|
||||
// Contact is the contact email addresses.
|
||||
Contact string `url:"contact"`
|
||||
// Directory is the URL of the ACME CA directory endpoint.
|
||||
Directory string `url:"directory,omitempty"`
|
||||
// EABHMACKey is the HMAC key for External Account Binding.
|
||||
EABHMACKey string `url:"eab-hmac-key,omitempty"`
|
||||
// EABKID is the Key Identifier for External Account Binding.
|
||||
EABKID string `url:"eab-kid,omitempty"`
|
||||
// Name is the ACME account config file name.
|
||||
Name string `url:"name,omitempty"`
|
||||
// TOS is the URL of CA TermsOfService - setting this indicates agreement.
|
||||
TOS string `url:"tos_url,omitempty"`
|
||||
}
|
||||
|
||||
// ACMEAccountCreateResponseBody contains the body from an ACME account create request.
|
||||
type ACMEAccountCreateResponseBody struct {
|
||||
Data *string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// ACMEAccountUpdateRequestBody contains the body for updating an existing ACME account.
|
||||
type ACMEAccountUpdateRequestBody struct {
|
||||
// Contact is the contact email addresses.
|
||||
Contact string `url:"contact,omitempty"`
|
||||
// Name is the ACME account config file name.
|
||||
Name string `url:"name,omitempty"`
|
||||
}
|
||||
|
||||
// ACMEAccountUpdateResponseBody contains the body from an ACME account update request.
|
||||
type ACMEAccountUpdateResponseBody struct {
|
||||
Data *string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// ACMEAccountDeleteResponseBody contains the body from an ACME account delete request.
|
||||
type ACMEAccountDeleteResponseBody struct {
|
||||
Data *string `json:"data,omitempty"`
|
||||
}
|
31
proxmox/cluster/acme/account/client.go
Normal file
31
proxmox/cluster/acme/account/client.go
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package account
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/tasks"
|
||||
)
|
||||
|
||||
// Client is an interface for accessing the Proxmox ACME management API.
|
||||
type Client struct {
|
||||
api.Client
|
||||
}
|
||||
|
||||
// ExpandPath expands a relative path to the Proxmox ACME management API path.
|
||||
func (c *Client) ExpandPath(path string) string {
|
||||
return fmt.Sprintf("cluster/acme/account/%s", path)
|
||||
}
|
||||
|
||||
// Tasks returns a client for managing ACME account tasks.
|
||||
func (c *Client) Tasks() *tasks.Client {
|
||||
return &tasks.Client{
|
||||
Client: c.Client,
|
||||
}
|
||||
}
|
29
proxmox/cluster/acme/client.go
Normal file
29
proxmox/cluster/acme/client.go
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package acme
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/account"
|
||||
)
|
||||
|
||||
// Client is an interface for accessing the Proxmox ACME API.
|
||||
type Client struct {
|
||||
api.Client
|
||||
}
|
||||
|
||||
// ExpandPath expands a relative path to a full cluster API path.
|
||||
func (c *Client) ExpandPath(path string) string {
|
||||
return fmt.Sprintf("cluster/acme/%s", path)
|
||||
}
|
||||
|
||||
// Account returns a client for managing the cluster's ACME account.
|
||||
func (c *Client) Account() *account.Client {
|
||||
return &account.Client{Client: c.Client}
|
||||
}
|
@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme"
|
||||
clusterfirewall "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/firewall"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||
@ -42,3 +43,8 @@ func (c *Client) HA() *ha.Client {
|
||||
func (c *Client) HardwareMapping() *mapping.Client {
|
||||
return &mapping.Client{Client: c}
|
||||
}
|
||||
|
||||
// ACME returns a client for managing the cluster's ACME features.
|
||||
func (c *Client) ACME() *acme.Client {
|
||||
return &acme.Client{Client: c}
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ import (
|
||||
// Temporary: while migrating to the TF framework, we need to copy the generated docs to the right place
|
||||
// for the resources / data sources that have been migrated.
|
||||
//go:generate cp -R ../build/docs-gen/guides/. ../docs/guides/
|
||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_acme_account.md ../docs/data-sources/
|
||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_acme_accounts.md ../docs/data-sources/
|
||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_apt_repository.md ../docs/data-sources/
|
||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_apt_standard_repository.md ../docs/data-sources/
|
||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_hagroup.md ../docs/data-sources/
|
||||
@ -40,6 +42,7 @@ import (
|
||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_version.md ../docs/data-sources/
|
||||
//go:generate cp ../build/docs-gen/data-sources/virtual_environment_vm2.md ../docs/data-sources/
|
||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_acl.md ../docs/resources/
|
||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_acme_account.md ../docs/resources/
|
||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_apt_repository.md ../docs/resources/
|
||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_apt_standard_repository.md ../docs/resources/
|
||||
//go:generate cp ../build/docs-gen/resources/virtual_environment_cluster_options.md ../docs/resources/
|
||||
|
Loading…
Reference in New Issue
Block a user