0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-07-01 11:02:59 +00:00
terraform-provider-proxmox/resource_virtual_environment_file.go

287 lines
6.6 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 main
import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/danitso/terraform-provider-proxmox/proxmox"
"github.com/hashicorp/terraform/helper/schema"
)
const (
mkResourceVirtualEnvironmentFileDatastoreID = "datastore_id"
mkResourceVirtualEnvironmentFileFileName = "file_name"
mkResourceVirtualEnvironmentFileOverrideFileName = "override_file_name"
mkResourceVirtualEnvironmentFileNodeName = "node_name"
mkResourceVirtualEnvironmentFileSource = "source"
mkResourceVirtualEnvironmentFileTemplate = "template"
)
func resourceVirtualEnvironmentFile() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentFileDatastoreID: &schema.Schema{
Type: schema.TypeString,
Description: "The datastore id",
Required: true,
ForceNew: true,
},
mkResourceVirtualEnvironmentFileFileName: &schema.Schema{
Type: schema.TypeString,
Description: "The datastore file name",
Computed: true,
},
mkResourceVirtualEnvironmentFileOverrideFileName: &schema.Schema{
Type: schema.TypeString,
Description: "The file name to use in the datastore (leave undefined to use source file name)",
Optional: true,
ForceNew: true,
Default: "",
},
mkResourceVirtualEnvironmentFileNodeName: &schema.Schema{
Type: schema.TypeString,
Description: "The node name",
Required: true,
ForceNew: true,
},
mkResourceVirtualEnvironmentFileSource: &schema.Schema{
Type: schema.TypeString,
Description: "The path to a file",
Required: true,
ForceNew: true,
},
mkResourceVirtualEnvironmentFileTemplate: &schema.Schema{
Type: schema.TypeBool,
Description: "Whether this is a container template",
Required: true,
ForceNew: true,
},
},
Create: resourceVirtualEnvironmentFileCreate,
Read: resourceVirtualEnvironmentFileRead,
Delete: resourceVirtualEnvironmentFileDelete,
}
}
func resourceVirtualEnvironmentFileCreate(d *schema.ResourceData, m interface{}) error {
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
datastoreID := d.Get(mkResourceVirtualEnvironmentFileDatastoreID).(string)
fileName, err := resourceVirtualEnvironmentFileGetFileName(d, m)
if err != nil {
return err
}
nodeName := d.Get(mkResourceVirtualEnvironmentFileNodeName).(string)
source := d.Get(mkResourceVirtualEnvironmentFileSource).(string)
template := d.Get(mkResourceVirtualEnvironmentFileTemplate).(bool)
var sourceReader io.Reader
if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") {
log.Printf("[DEBUG] Downloading file '%s'", source)
res, err := http.Get(source)
if err != nil {
return err
}
defer res.Body.Close()
tempDownloadedFile, err := ioutil.TempFile("", "download")
if err != nil {
return err
}
tempDownloadedFileName := tempDownloadedFile.Name()
_, err = io.Copy(tempDownloadedFile, res.Body)
if err != nil {
tempDownloadedFile.Close()
return err
}
tempDownloadedFile.Close()
defer os.Remove(tempDownloadedFileName)
file, err := os.Open(tempDownloadedFileName)
if err != nil {
return err
}
defer file.Close()
sourceReader = file
} else {
file, err := os.Open(source)
if err != nil {
return err
}
defer file.Close()
sourceReader = file
}
contentType := "iso"
if template {
contentType = "vztmpl"
}
body := &proxmox.VirtualEnvironmentDatastoreUploadRequestBody{
ContentType: contentType,
DatastoreID: datastoreID,
FileName: *fileName,
FileReader: sourceReader,
NodeName: nodeName,
}
_, err = veClient.UploadFileToDatastore(body)
if err != nil {
return err
}
volumeID, err := resourceVirtualEnvironmentFileGetVolumeID(d, m)
if err != nil {
return err
}
d.SetId(*volumeID)
return resourceVirtualEnvironmentFileRead(d, m)
}
func resourceVirtualEnvironmentFileGetFileName(d *schema.ResourceData, m interface{}) (*string, error) {
fileName := d.Get(mkResourceVirtualEnvironmentFileOverrideFileName).(string)
source := d.Get(mkResourceVirtualEnvironmentFileSource).(string)
if fileName == "" {
if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") {
downloadURL, err := url.ParseRequestURI(source)
if err != nil {
return nil, err
}
path := strings.Split(downloadURL.Path, "/")
fileName = path[len(path)-1]
if fileName == "" {
return nil, errors.New("Failed to determine file name from source URL")
}
} else {
fileName = filepath.Base(source)
}
}
return &fileName, nil
}
func resourceVirtualEnvironmentFileGetVolumeID(d *schema.ResourceData, m interface{}) (*string, error) {
contentType := "iso"
fileName, err := resourceVirtualEnvironmentFileGetFileName(d, m)
if err != nil {
return nil, err
}
datastoreID := d.Get(mkResourceVirtualEnvironmentFileDatastoreID).(string)
template := d.Get(mkResourceVirtualEnvironmentFileTemplate).(bool)
if template {
contentType = "vztmpl"
}
volumeID := fmt.Sprintf("%s:%s/%s", datastoreID, contentType, *fileName)
return &volumeID, nil
}
func resourceVirtualEnvironmentFileRead(d *schema.ResourceData, m interface{}) error {
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
datastoreID := d.Get(mkResourceVirtualEnvironmentFileDatastoreID).(string)
nodeName := d.Get(mkResourceVirtualEnvironmentFileNodeName).(string)
list, err := veClient.ListDatastoreFiles(nodeName, datastoreID)
if err != nil {
return err
}
for _, v := range list {
if v.VolumeID == d.Id() {
fileName, _ := resourceVirtualEnvironmentFileGetFileName(d, m)
d.Set(mkResourceVirtualEnvironmentFileFileName, *fileName)
return nil
}
}
d.SetId("")
return nil
}
func resourceVirtualEnvironmentFileDelete(d *schema.ResourceData, m interface{}) error {
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
datastoreID := d.Get(mkResourceVirtualEnvironmentFileDatastoreID).(string)
nodeName := d.Get(mkResourceVirtualEnvironmentFileNodeName).(string)
err = veClient.DeleteDatastoreFile(nodeName, datastoreID, d.Id())
if err != nil {
if strings.Contains(err.Error(), "HTTP 404") {
d.SetId("")
return nil
}
return err
}
d.SetId("")
return nil
}