From 44aeabbc28a60a46021e3c5b341fc1848d68c861 Mon Sep 17 00:00:00 2001 From: Dan Petersen Date: Sat, 7 Dec 2019 21:15:59 +0100 Subject: [PATCH] Latest work --- CHANGELOG.md | 1 + README.md | 9 +++ ...ource_virtual_environment_access_groups.go | 67 +++++++++++++++++++ ..._virtual_environment_access_groups_test.go | 38 +++++++++++ data_source_virtual_environment_version.go | 2 +- ...source_virtual_environment_version_test.go | 1 + ...ource_virtual_environment_access_groups.tf | 8 +++ ...data_source_virtual_environment_version.tf | 12 ++-- provider.go | 3 +- proxmox/virtual_environment.go | 61 ++++++++++++++++- proxmox/virtual_environment_access_groups.go | 36 ++++++++++ proxmox/virtual_environment_authentication.go | 7 +- proxmox/virtual_environment_version.go | 32 +-------- 13 files changed, 232 insertions(+), 45 deletions(-) create mode 100644 data_source_virtual_environment_access_groups.go create mode 100644 data_source_virtual_environment_access_groups_test.go create mode 100644 example/data_source_virtual_environment_access_groups.tf create mode 100644 proxmox/virtual_environment_access_groups.go diff --git a/CHANGELOG.md b/CHANGELOG.md index d969fcd0..5d434fe6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,5 @@ FEATURES: +* **New Data Source:** `proxmox_virtual_environment_access_groups` * **New Data Source:** `proxmox_virtual_environment_version` diff --git a/README.md b/README.md index 44da6813..d8d299e4 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,15 @@ If you're building the provider, follow the instructions to [install it as a plu #### Virtual Environment +##### Access Groups (proxmox_virtual_environment_access_groups) + +###### Arguments +This data source doesn't accept arguments. + +###### Attributes +* `comments` - The group comments. +* `ids` - The group ids. + ##### Version (proxmox_virtual_environment_version) ###### Arguments diff --git a/data_source_virtual_environment_access_groups.go b/data_source_virtual_environment_access_groups.go new file mode 100644 index 00000000..f16dda8f --- /dev/null +++ b/data_source_virtual_environment_access_groups.go @@ -0,0 +1,67 @@ +/* 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" + + "github.com/hashicorp/terraform/helper/schema" +) + +const ( + mkDataSourceVirtualEnvironmentAccessGroupsComments = "comments" + mkDataSourceVirtualEnvironmentAccessGroupsIDs = "ids" +) + +// dataSourceVirtualEnvironmentAccessGroups retrieves a list of access groups. +func dataSourceVirtualEnvironmentAccessGroups() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + mkDataSourceVirtualEnvironmentAccessGroupsComments: &schema.Schema{ + Type: schema.TypeList, + Description: "The group comments", + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + mkDataSourceVirtualEnvironmentAccessGroupsIDs: &schema.Schema{ + Type: schema.TypeList, + Description: "The group ids", + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + Read: dataSourceVirtualEnvironmentAccessGroupsRead, + } +} + +// dataSourceVirtualEnvironmentAccessGroupsRead retrieves a list of access groups. +func dataSourceVirtualEnvironmentAccessGroupsRead(d *schema.ResourceData, m interface{}) error { + config := m.(providerConfiguration) + + if config.veClient == nil { + return errors.New("You must specify the virtual environment details in the provider configuration to use this data source") + } + + list, err := config.veClient.ListAccessGroups() + + if err != nil { + return err + } + + comments := make([]interface{}, len(list)) + ids := make([]interface{}, len(list)) + + for i, v := range list { + comments[i] = v.Comment + ids[i] = v.ID + } + + d.SetId("access_groups") + + d.Set(mkDataSourceVirtualEnvironmentAccessGroupsComments, comments) + d.Set(mkDataSourceVirtualEnvironmentAccessGroupsIDs, ids) + + return nil +} diff --git a/data_source_virtual_environment_access_groups_test.go b/data_source_virtual_environment_access_groups_test.go new file mode 100644 index 00000000..65cb7202 --- /dev/null +++ b/data_source_virtual_environment_access_groups_test.go @@ -0,0 +1,38 @@ +/* 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 ( + "testing" +) + +// TestDataSourceVirtualEnvironmentAccessGroupsInstantiation tests whether the DataSourceVirtualEnvironmentAccessGroups instance can be instantiated. +func TestDataSourceVirtualEnvironmentAccessGroupsInstantiation(t *testing.T) { + s := dataSourceVirtualEnvironmentAccessGroups() + + if s == nil { + t.Fatalf("Cannot instantiate dataSourceVirtualEnvironmentAccessGroups") + } +} + +// TestDataSourceVirtualEnvironmentAccessGroupsSchema tests the dataSourceVirtualEnvironmentAccessGroups schema. +func TestDataSourceVirtualEnvironmentAccessGroupsSchema(t *testing.T) { + s := dataSourceVirtualEnvironmentAccessGroups() + + attributeKeys := []string{ + mkDataSourceVirtualEnvironmentAccessGroupsComments, + mkDataSourceVirtualEnvironmentAccessGroupsIDs, + } + + for _, v := range attributeKeys { + if s.Schema[v] == nil { + t.Fatalf("Error in dataSourceVirtualEnvironmentAccessGroups.Schema: Missing attribute \"%s\"", v) + } + + if s.Schema[v].Computed != true { + t.Fatalf("Error in dataSourceVirtualEnvironmentAccessGroups.Schema: Attribute \"%s\" is not computed", v) + } + } +} diff --git a/data_source_virtual_environment_version.go b/data_source_virtual_environment_version.go index f1869ec5..b551f82d 100644 --- a/data_source_virtual_environment_version.go +++ b/data_source_virtual_environment_version.go @@ -64,7 +64,7 @@ func dataSourceVirtualEnvironmentVersionRead(d *schema.ResourceData, m interface return err } - d.SetId(version.Version) + d.SetId("version") d.Set(mkDataSourceVirtualEnvironmentVersionKeyboard, version.Keyboard) d.Set(mkDataSourceVirtualEnvironmentVersionRelease, version.Release) diff --git a/data_source_virtual_environment_version_test.go b/data_source_virtual_environment_version_test.go index 4b55feaf..825b0c1f 100644 --- a/data_source_virtual_environment_version_test.go +++ b/data_source_virtual_environment_version_test.go @@ -22,6 +22,7 @@ func TestDataSourceVirtualEnvironmentVersionSchema(t *testing.T) { s := dataSourceVirtualEnvironmentVersion() attributeKeys := []string{ + mkDataSourceVirtualEnvironmentVersionKeyboard, mkDataSourceVirtualEnvironmentVersionRelease, mkDataSourceVirtualEnvironmentVersionRepositoryID, mkDataSourceVirtualEnvironmentVersionVersion, diff --git a/example/data_source_virtual_environment_access_groups.tf b/example/data_source_virtual_environment_access_groups.tf new file mode 100644 index 00000000..0a03f909 --- /dev/null +++ b/example/data_source_virtual_environment_access_groups.tf @@ -0,0 +1,8 @@ +data "proxmox_virtual_environment_access_groups" "example" {} + +output "data_proxmox_virtual_environment_access_groups" { + value = "${map( + "comments", data.proxmox_virtual_environment_access_groups.example.comments, + "ids", data.proxmox_virtual_environment_access_groups.example.ids, + )}" +} diff --git a/example/data_source_virtual_environment_version.tf b/example/data_source_virtual_environment_version.tf index 000de378..ed7b2236 100644 --- a/example/data_source_virtual_environment_version.tf +++ b/example/data_source_virtual_environment_version.tf @@ -1,10 +1,10 @@ -data "proxmox_virtual_environment_version" "ve_version" {} +data "proxmox_virtual_environment_version" "example" {} -output "proxmox_virtual_environment_version" { +output "data_proxmox_virtual_environment_version" { value = "${map( - "keyboard", data.proxmox_virtual_environment_version.ve_version.keyboard, - "release", data.proxmox_virtual_environment_version.ve_version.release, - "repository_id", data.proxmox_virtual_environment_version.ve_version.repository_id, - "version", data.proxmox_virtual_environment_version.ve_version.version, + "keyboard", data.proxmox_virtual_environment_version.example.keyboard, + "release", data.proxmox_virtual_environment_version.example.release, + "repository_id", data.proxmox_virtual_environment_version.example.repository_id, + "version", data.proxmox_virtual_environment_version.example.version, )}" } diff --git a/provider.go b/provider.go index 26c48c50..b341bde4 100644 --- a/provider.go +++ b/provider.go @@ -26,7 +26,8 @@ func Provider() *schema.Provider { return &schema.Provider{ ConfigureFunc: providerConfigure, DataSourcesMap: map[string]*schema.Resource{ - "proxmox_virtual_environment_version": dataSourceVirtualEnvironmentVersion(), + "proxmox_virtual_environment_access_groups": dataSourceVirtualEnvironmentAccessGroups(), + "proxmox_virtual_environment_version": dataSourceVirtualEnvironmentVersion(), }, ResourcesMap: map[string]*schema.Resource{}, Schema: map[string]*schema.Schema{ diff --git a/proxmox/virtual_environment.go b/proxmox/virtual_environment.go index e29b66e8..7719b8c4 100644 --- a/proxmox/virtual_environment.go +++ b/proxmox/virtual_environment.go @@ -5,7 +5,9 @@ package proxmox import ( + "bytes" "crypto/tls" + "encoding/json" "errors" "fmt" "net/http" @@ -13,7 +15,13 @@ import ( "strings" ) -const basePathJSONAPI = "api2/json" +const ( + basePathJSONAPI = "api2/json" + hmDELETE = "DELETE" + hmGET = "GET" + hmPOST = "POST" + hmPUT = "PUT" +) // VirtualEnvironmentClient implements an API client for the Proxmox Virtual Environment API. type VirtualEnvironmentClient struct { @@ -63,8 +71,55 @@ func NewVirtualEnvironmentClient(endpoint, username, password string, insecure b }, nil } -// ValidateResponse ensures that a response is valid. -func (c *VirtualEnvironmentClient) ValidateResponse(res *http.Response) error { +// DoRequest performs a HTTP request against a JSON API endpoint. +func (c *VirtualEnvironmentClient) DoRequest(method, path string, requestBody interface{}, responseBody interface{}) error { + jsonRequestBody := new(bytes.Buffer) + + if requestBody != nil { + err := json.NewEncoder(jsonRequestBody).Encode(requestBody) + + if err != nil { + return fmt.Errorf("Failed to encode HTTP %s request (path: %s)", method, path) + } + } + + req, err := http.NewRequest(method, fmt.Sprintf("%s/%s/%s", c.Endpoint, basePathJSONAPI, path), jsonRequestBody) + + if err != nil { + return fmt.Errorf("Failed to create HTTP %s request (path: %s)", method, path) + } + + err = c.AuthenticateRequest(req) + + if err != nil { + return err + } + + req.Header.Add("Content-Type", "application/json") + + res, err := c.httpClient.Do(req) + + if err != nil { + return fmt.Errorf("Failed to perform HTTP %s request (path: %s)", method, path) + } + + err = c.ValidateResponseCode(res) + + if err != nil { + return err + } + + err = json.NewDecoder(res.Body).Decode(responseBody) + + if err != nil { + return fmt.Errorf("Failed to decode HTTP %s response (path: %s)", method, path) + } + + return nil +} + +// ValidateResponseCode ensures that a response is valid. +func (c *VirtualEnvironmentClient) ValidateResponseCode(res *http.Response) error { if res.StatusCode < 200 || res.StatusCode >= 300 { switch res.StatusCode { case 401: diff --git a/proxmox/virtual_environment_access_groups.go b/proxmox/virtual_environment_access_groups.go new file mode 100644 index 00000000..a1181deb --- /dev/null +++ b/proxmox/virtual_environment_access_groups.go @@ -0,0 +1,36 @@ +/* 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 proxmox + +import ( + "errors" +) + +// VirtualEnvironmentAccessGroupListResponseBody contains the body from an access group list response. +type VirtualEnvironmentAccessGroupListResponseBody struct { + Data []*VirtualEnvironmentAccessGroupListResponseData `json:"data,omitempty"` +} + +// VirtualEnvironmentAccessGroupListResponseData contains the data from an access group list response. +type VirtualEnvironmentAccessGroupListResponseData struct { + Comment string `json:"comment"` + ID string `json:"groupid"` +} + +// ListAccessGroups retrieves a list of access groups. +func (c *VirtualEnvironmentClient) ListAccessGroups() ([]*VirtualEnvironmentAccessGroupListResponseData, error) { + resBody := &VirtualEnvironmentAccessGroupListResponseBody{} + err := c.DoRequest(hmGET, "access/groups", nil, resBody) + + if err != nil { + return nil, err + } + + if resBody.Data == nil { + return nil, errors.New("The server did not include a data object in the response") + } + + return resBody.Data, nil +} diff --git a/proxmox/virtual_environment_authentication.go b/proxmox/virtual_environment_authentication.go index bc3a57fc..8aeaae56 100644 --- a/proxmox/virtual_environment_authentication.go +++ b/proxmox/virtual_environment_authentication.go @@ -29,6 +29,7 @@ type VirtualEnvironmentAuthenticationResponseCapabilities struct { // VirtualEnvironmentAuthenticationResponseData contains the data from an authentication response. type VirtualEnvironmentAuthenticationResponseData struct { + ClusterName string `json:"clustername,omitempty"` CSRFPreventionToken string `json:"CSRFPreventionToken"` Capabilities *VirtualEnvironmentAuthenticationResponseCapabilities `json:"cap,omitempty"` Ticket string `json:"ticket"` @@ -42,7 +43,7 @@ func (c *VirtualEnvironmentClient) Authenticate(reset bool) error { } body := bytes.NewBufferString(fmt.Sprintf("username=%s&password=%s", url.QueryEscape(c.Username), url.QueryEscape(c.Password))) - req, err := http.NewRequest("POST", fmt.Sprintf("%s/%s/access/ticket", c.Endpoint, basePathJSONAPI), body) + req, err := http.NewRequest(hmPOST, fmt.Sprintf("%s/%s/access/ticket", c.Endpoint, basePathJSONAPI), body) if err != nil { return errors.New("Failed to create authentication request") @@ -56,7 +57,7 @@ func (c *VirtualEnvironmentClient) Authenticate(reset bool) error { return errors.New("Failed to retrieve authentication response") } - err = c.ValidateResponse(res) + err = c.ValidateResponseCode(res) if err != nil { return err @@ -103,8 +104,6 @@ func (c *VirtualEnvironmentClient) AuthenticateRequest(req *http.Request) error Value: c.authenticationData.Ticket, }) - req.Header.Add("Content-Type", "application/json") - if req.Method != "GET" { req.Header.Add("CSRFPreventionToken", c.authenticationData.CSRFPreventionToken) } diff --git a/proxmox/virtual_environment_version.go b/proxmox/virtual_environment_version.go index 149c05e2..346d7ecc 100644 --- a/proxmox/virtual_environment_version.go +++ b/proxmox/virtual_environment_version.go @@ -5,11 +5,7 @@ package proxmox import ( - "bytes" - "encoding/json" "errors" - "fmt" - "net/http" ) // VirtualEnvironmentVersionResponseBody contains the body from a version response. @@ -27,37 +23,13 @@ type VirtualEnvironmentVersionResponseData struct { // Version retrieves the version information. func (c *VirtualEnvironmentClient) Version() (*VirtualEnvironmentVersionResponseData, error) { - req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s/version", c.Endpoint, basePathJSONAPI), new(bytes.Buffer)) - - if err != nil { - return nil, errors.New("Failed to create version information request") - } - - err = c.AuthenticateRequest(req) + resBody := &VirtualEnvironmentVersionResponseBody{} + err := c.DoRequest(hmGET, "version", nil, resBody) if err != nil { return nil, err } - res, err := c.httpClient.Do(req) - - if err != nil { - return nil, errors.New("Failed to perform version information request") - } - - err = c.ValidateResponse(res) - - if err != nil { - return nil, err - } - - resBody := VirtualEnvironmentVersionResponseBody{} - err = json.NewDecoder(res.Body).Decode(&resBody) - - if err != nil { - return nil, errors.New("Failed to decode version information response") - } - if resBody.Data == nil { return nil, errors.New("The server did not include a data object in the response") }