mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-30 10:33:46 +00:00
move `types` back from `internal` to `proxmox` and adjust a few other types, to make sure `proxmox` package is not dependent on anything else, and therefore can be extracted to a separate repo (#423)
348 lines
11 KiB
Go
348 lines
11 KiB
Go
/*
|
|
* 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 resource
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
|
|
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
|
|
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
|
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
|
|
)
|
|
|
|
const (
|
|
dvResourceVirtualEnvironmentCertificateCertificateChain = ""
|
|
dvResourceVirtualEnvironmentCertificateOverwrite = false
|
|
|
|
mkResourceVirtualEnvironmentCertificateCertificate = "certificate"
|
|
mkResourceVirtualEnvironmentCertificateCertificateChain = "certificate_chain"
|
|
mkResourceVirtualEnvironmentCertificateFileName = "file_name"
|
|
mkResourceVirtualEnvironmentCertificateIssuer = "issuer"
|
|
mkResourceVirtualEnvironmentCertificateNodeName = "node_name"
|
|
mkResourceVirtualEnvironmentCertificateExpirationDate = "expiration_date"
|
|
mkResourceVirtualEnvironmentCertificateOverwrite = "overwrite"
|
|
mkResourceVirtualEnvironmentCertificatePrivateKey = "private_key"
|
|
mkResourceVirtualEnvironmentCertificatePublicKeySize = "public_key_size"
|
|
mkResourceVirtualEnvironmentCertificatePublicKeyType = "public_key_type"
|
|
mkResourceVirtualEnvironmentCertificateSSLFingerprint = "ssl_fingerprint"
|
|
mkResourceVirtualEnvironmentCertificateStartDate = "start_date"
|
|
mkResourceVirtualEnvironmentCertificateSubject = "subject"
|
|
mkResourceVirtualEnvironmentCertificateSubjectAlternativeNames = "subject_alternative_names"
|
|
)
|
|
|
|
// Certificate returns a resource that manages a certificate.
|
|
func Certificate() *schema.Resource {
|
|
return &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
mkResourceVirtualEnvironmentCertificateCertificate: {
|
|
Type: schema.TypeString,
|
|
Description: "The PEM encoded certificate",
|
|
Required: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateCertificateChain: {
|
|
Type: schema.TypeString,
|
|
Description: "The PEM encoded certificate chain",
|
|
Optional: true,
|
|
Default: dvResourceVirtualEnvironmentCertificateCertificateChain,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateExpirationDate: {
|
|
Type: schema.TypeString,
|
|
Description: "The expiration date",
|
|
Computed: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateFileName: {
|
|
Type: schema.TypeString,
|
|
Description: "The file name",
|
|
Computed: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateIssuer: {
|
|
Type: schema.TypeString,
|
|
Description: "The issuer",
|
|
Computed: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateNodeName: {
|
|
Type: schema.TypeString,
|
|
Description: "The node name",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateOverwrite: {
|
|
Type: schema.TypeBool,
|
|
Description: "Whether to overwrite an existing certificate",
|
|
Optional: true,
|
|
Default: dvResourceVirtualEnvironmentCertificateOverwrite,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificatePrivateKey: {
|
|
Type: schema.TypeString,
|
|
Description: "The PEM encoded private key",
|
|
Required: true,
|
|
Sensitive: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificatePublicKeySize: {
|
|
Type: schema.TypeInt,
|
|
Description: "The public key size",
|
|
Computed: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificatePublicKeyType: {
|
|
Type: schema.TypeString,
|
|
Description: "The public key type",
|
|
Computed: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateSSLFingerprint: {
|
|
Type: schema.TypeString,
|
|
Description: "The SSL fingerprint",
|
|
Computed: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateStartDate: {
|
|
Type: schema.TypeString,
|
|
Description: "The start date",
|
|
Computed: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateSubject: {
|
|
Type: schema.TypeString,
|
|
Description: "The subject",
|
|
Computed: true,
|
|
},
|
|
mkResourceVirtualEnvironmentCertificateSubjectAlternativeNames: {
|
|
Type: schema.TypeList,
|
|
Description: "The subject alternative names",
|
|
Computed: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
},
|
|
CreateContext: certificateCreate,
|
|
ReadContext: certificateRead,
|
|
UpdateContext: certificateUpdate,
|
|
DeleteContext: certificateDelete,
|
|
}
|
|
}
|
|
|
|
func certificateCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
|
|
diags := certificateUpdate(ctx, d, m)
|
|
if diags.HasError() {
|
|
return diags
|
|
}
|
|
|
|
nodeName := d.Get(mkResourceVirtualEnvironmentCertificateNodeName).(string)
|
|
|
|
d.SetId(fmt.Sprintf("%s_certificate", nodeName))
|
|
|
|
return nil
|
|
}
|
|
|
|
func certificateGetUpdateBody(d *schema.ResourceData) *nodes.CertificateUpdateRequestBody {
|
|
certificate := d.Get(mkResourceVirtualEnvironmentCertificateCertificate).(string)
|
|
certificateChain := d.Get(mkResourceVirtualEnvironmentCertificateCertificateChain).(string)
|
|
overwrite := types.CustomBool(d.Get(mkResourceVirtualEnvironmentCertificateOverwrite).(bool))
|
|
privateKey := d.Get(mkResourceVirtualEnvironmentCertificatePrivateKey).(string)
|
|
|
|
combinedCertificates := strings.TrimSpace(certificate) + "\n"
|
|
|
|
if certificateChain != "" {
|
|
combinedCertificates += strings.TrimSpace(certificateChain) + "\n"
|
|
}
|
|
|
|
force := overwrite
|
|
|
|
if d.Id() != "" {
|
|
force = true
|
|
}
|
|
|
|
restart := types.CustomBool(true)
|
|
|
|
body := &nodes.CertificateUpdateRequestBody{
|
|
Certificates: combinedCertificates,
|
|
Force: &force,
|
|
PrivateKey: &privateKey,
|
|
Restart: &restart,
|
|
}
|
|
|
|
return body
|
|
}
|
|
|
|
func certificateRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
|
|
var diags diag.Diagnostics
|
|
|
|
config := m.(proxmoxtf.ProviderConfiguration)
|
|
api, err := config.GetClient()
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
nodeName := d.Get(mkResourceVirtualEnvironmentCertificateNodeName).(string)
|
|
|
|
list, err := api.Node(nodeName).ListCertificates(ctx)
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateCertificate, "")
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateCertificateChain, "")
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
certificateChain := d.Get(mkResourceVirtualEnvironmentCertificateCertificateChain).(string)
|
|
|
|
for _, c := range *list {
|
|
if c.FileName != nil && *c.FileName == "pveproxy-ssl.pem" {
|
|
if c.Certificates != nil {
|
|
newCertificate := ""
|
|
newCertificateChain := ""
|
|
|
|
if certificateChain != "" {
|
|
certificates := strings.Split(strings.TrimSpace(*c.Certificates), "\n")
|
|
newCertificate = certificates[0] + "\n"
|
|
|
|
if len(certificates) > 1 {
|
|
newCertificateChain = strings.Join(certificates[1:], "\n") + "\n"
|
|
}
|
|
} else {
|
|
newCertificate = *c.Certificates
|
|
}
|
|
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateCertificate, newCertificate)
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
err = d.Set(
|
|
mkResourceVirtualEnvironmentCertificateCertificateChain,
|
|
newCertificateChain,
|
|
)
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
}
|
|
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateFileName, *c.FileName)
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
if c.NotAfter != nil {
|
|
t := time.Time(*c.NotAfter)
|
|
err = d.Set(
|
|
mkResourceVirtualEnvironmentCertificateExpirationDate,
|
|
t.UTC().Format(time.RFC3339),
|
|
)
|
|
} else {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateExpirationDate, "")
|
|
}
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
if c.Issuer != nil {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateIssuer, *c.Issuer)
|
|
} else {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateIssuer, "")
|
|
}
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
if c.PublicKeyBits != nil {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificatePublicKeySize, *c.PublicKeyBits)
|
|
} else {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificatePublicKeySize, 0)
|
|
}
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
if c.PublicKeyType != nil {
|
|
pkType := *c.PublicKeyType
|
|
for _, pkt := range []string{"ecdsa", "dsa", "rsa"} {
|
|
if strings.Contains(pkType, pkt) {
|
|
pkType = pkt
|
|
}
|
|
}
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificatePublicKeyType, pkType)
|
|
} else {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificatePublicKeyType, "")
|
|
}
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
if c.Fingerprint != nil {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateSSLFingerprint, *c.Fingerprint)
|
|
} else {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateSSLFingerprint, "")
|
|
}
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
if c.NotBefore != nil {
|
|
t := time.Time(*c.NotBefore)
|
|
err = d.Set(
|
|
mkResourceVirtualEnvironmentCertificateStartDate,
|
|
t.UTC().Format(time.RFC3339),
|
|
)
|
|
} else {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateStartDate, "")
|
|
}
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
if c.Subject != nil {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateSubject, *c.Subject)
|
|
} else {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateSubject, "")
|
|
}
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
|
|
if c.SubjectAlternativeNames != nil {
|
|
sanList := make([]interface{}, len(*c.SubjectAlternativeNames))
|
|
for i, san := range *c.SubjectAlternativeNames {
|
|
sanList[i] = san
|
|
}
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateSubjectAlternativeNames, sanList)
|
|
} else {
|
|
err = d.Set(mkResourceVirtualEnvironmentCertificateSubjectAlternativeNames, []interface{}{})
|
|
}
|
|
diags = append(diags, diag.FromErr(err)...)
|
|
}
|
|
}
|
|
|
|
return diags
|
|
}
|
|
|
|
func certificateUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
|
|
config := m.(proxmoxtf.ProviderConfiguration)
|
|
api, err := config.GetClient()
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
nodeName := d.Get(mkResourceVirtualEnvironmentCertificateNodeName).(string)
|
|
|
|
body := certificateGetUpdateBody(d)
|
|
|
|
err = api.Node(nodeName).UpdateCertificate(ctx, body)
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
return certificateRead(ctx, d, m)
|
|
}
|
|
|
|
func certificateDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
|
|
config := m.(proxmoxtf.ProviderConfiguration)
|
|
api, err := config.GetClient()
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
nodeName := d.Get(mkResourceVirtualEnvironmentCertificateNodeName).(string)
|
|
|
|
restart := types.CustomBool(true)
|
|
|
|
err = api.Node(nodeName).DeleteCertificate(
|
|
ctx,
|
|
&nodes.CertificateDeleteRequestBody{
|
|
Restart: &restart,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
d.SetId("")
|
|
|
|
return nil
|
|
}
|