Add account handler and refine other code. No testing yet!
This commit is contained in:
136
decort/account_data_source.go
Normal file
136
decort/account_data_source.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
// "net/url"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenAccount(d *schema.ResourceData, acc_facts string) error {
|
||||||
|
// NOTE: this function modifies ResourceData argument - as such it should never be called
|
||||||
|
// from resourceAccountExists(...) method
|
||||||
|
|
||||||
|
// log.Debugf("flattenAccount: ready to decode response body from %q", CloudspacesGetAPI)
|
||||||
|
details := AccountRecord{}
|
||||||
|
err := json.Unmarshal([]byte(rg_facts), &details)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("flattenAccount: decoded Account name %q / ID %d, status %q",
|
||||||
|
details.Name, details.ID, details.Status)
|
||||||
|
|
||||||
|
d.SetId(fmt.Sprintf("%d", details.ID))
|
||||||
|
d.Set("name", details.Name)
|
||||||
|
d.Set("status", details.Status)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccountRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
acc_facts, err := utilityAccountCheckPresence(d, m)
|
||||||
|
if acc_facts == "" {
|
||||||
|
// if empty string is returned from utilityAccountCheckPresence then there is no
|
||||||
|
// such account and err tells so - just return it to the calling party
|
||||||
|
d.SetId("") // ensure ID is empty in this case
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenAccount(d, acc_facts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccount() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceAccountRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Name of the account. Names are case sensitive and unique.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the account. If account ID is specified, then account name is ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"status": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Current status of the account."
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We keep the following attributes commented out, as we are not implementing account
|
||||||
|
management with Terraform plugin, so we do not need this extra info.
|
||||||
|
|
||||||
|
"quota": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: quotaRgSubresourceSchema(), // this is a dictionary
|
||||||
|
},
|
||||||
|
Description: "Quotas on the resources for this account and all its resource groups.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"resource_groups": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "IDs of resource groups in this account."
|
||||||
|
},
|
||||||
|
|
||||||
|
"vins": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "IDs of VINSes created at the account level."
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
153
decort/account_utility.go
Normal file
153
decort/account_utility.go
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
// "strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
// "github.com/hashicorp/terraform/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountCheckPresence(d *schema.ResourceData, m interface{}) (string, error) {
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
url_values := &url.Values{}
|
||||||
|
|
||||||
|
acc_id, arg_set := d.GetOk("account_id")
|
||||||
|
if arg_set {
|
||||||
|
// get Account right away by its ID
|
||||||
|
log.Debugf("utilityAccountCheckPresence: locating Account by its ID %d", acc_id.(int))
|
||||||
|
url_values.Add("accountId", fmt.Sprintf("%d", acc_id.(int)))
|
||||||
|
api_resp, err := controller.decortAPICall("POST", AccountsGetAPI, url_values)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return api_resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
acc_name, arg_set := d.GetOk("name")
|
||||||
|
if !arg_set {
|
||||||
|
// neither ID nor name - no account for you!
|
||||||
|
return "", fmt.Error("Cannot check account presence if name is empty and no account ID specified.")
|
||||||
|
}
|
||||||
|
|
||||||
|
api_resp, err := controller.decortAPICall("POST", AccountsListAPI, url_values)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// log.Debugf("%s", api_resp)
|
||||||
|
// log.Debugf("utilityAccountCheckPresence: ready to decode response body from %q", AccountsListAPI)
|
||||||
|
acc_list := AccountsListResp{}
|
||||||
|
err = json.Unmarshal([]byte(api_resp), &acc_list)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountCheckPresence: traversing decoded Json of length %d", len(model))
|
||||||
|
for index, item := range acc_list {
|
||||||
|
// match by account name
|
||||||
|
if item.Name == acc_name.(string) {
|
||||||
|
log.Debugf("utilityAccountCheckPresence: match account name %q / ID %d at index %d",
|
||||||
|
item.Name, item.ID, index)
|
||||||
|
|
||||||
|
// NB: unlike accounts/get API, accounts/list API returns abridged set of account info,
|
||||||
|
// for instance it does not return quotas
|
||||||
|
|
||||||
|
reencoded_item, err := json.Marshal(item)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return reencoded_item.(string), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("Cannot find account name %q owned by account ID %d", name, validated_account_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func utilityGetAccountIdBySchema(d *schema.ResourceData, m interface{}) (int, error) {
|
||||||
|
/*
|
||||||
|
This function expects schema that contains the following two elements:
|
||||||
|
|
||||||
|
"account_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: Optional,
|
||||||
|
Description: "Name of the account, ....",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the account, ....",
|
||||||
|
},
|
||||||
|
|
||||||
|
Then it will check, which argument is set, and if account name is present, it will
|
||||||
|
initiate API calls to the DECORT cloud controller and try to match relevant account
|
||||||
|
by the name.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
account_id, arg_set := d.GetOk("account_id")
|
||||||
|
if arg_set {
|
||||||
|
if account_id.(int) > 0 {
|
||||||
|
return account_id.(int), nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Error("Account ID must be positive, if set.")
|
||||||
|
}
|
||||||
|
|
||||||
|
account_name, arg_set := d.GetOk("account_name")
|
||||||
|
if !arg_set {
|
||||||
|
return 0, fmt.Error("Non-empty account name or positive account ID must be specified.")
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
url_values := &url.Values{}
|
||||||
|
body_string, err := controller.decortAPICall("POST", AccountsListAPI, url_values)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
model := AccountsListResp{}
|
||||||
|
err = json.Unmarshal([]byte(body_string), &model)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityGetAccountIdBySchema: traversing decoded Json of length %d", len(model))
|
||||||
|
for index, item := range model {
|
||||||
|
// need to match Account by name
|
||||||
|
if item.Name == account_name.(string) {
|
||||||
|
log.Debugf("utilityGetAccountIdBySchema: match Account name %q / ID %d at index %d",
|
||||||
|
item.Name, item.ID, index)
|
||||||
|
return item.ID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("Cannot find account %q for the current user. Check account name and your access rights", account_name.(string))
|
||||||
|
}
|
||||||
@@ -49,8 +49,20 @@ func parseComputeDisks(disks []DiskRecord) []interface{} {
|
|||||||
for i, value := range disks {
|
for i, value := range disks {
|
||||||
// keys in this map should correspond to the Schema definition
|
// keys in this map should correspond to the Schema definition
|
||||||
// as returned by dataSourceDiskSchemaMake()
|
// as returned by dataSourceDiskSchemaMake()
|
||||||
elem[" attribute "] = value. attribute
|
elem["name"] = value.Name
|
||||||
...
|
elem["disk_id"] = value.ID
|
||||||
|
elem["account_id"] = value.AccountID
|
||||||
|
elem["account_name"] = value.AccountName
|
||||||
|
elem["description"] = value.Desc
|
||||||
|
elem["image_id"] = value.ImageID
|
||||||
|
elem["size"] = value.SizeMax
|
||||||
|
elem["type"] = value.Type
|
||||||
|
elem["sep_id"] = value.SepID
|
||||||
|
elem["sep_type"] = value.SepType
|
||||||
|
elem["pool"] = value.Pool
|
||||||
|
elem["status"] = value.Status
|
||||||
|
elem["tech_status"] = value.TechStatus
|
||||||
|
elem["compute_id"] = value.ComputeID
|
||||||
result[i] = elem
|
result[i] = elem
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,8 +83,22 @@ func parseComputeInterfaces(ifaces []InterfaceRecord) []interface{} {
|
|||||||
for i, value := range ifaces {
|
for i, value := range ifaces {
|
||||||
// Keys in this map should correspond to the Schema definition
|
// Keys in this map should correspond to the Schema definition
|
||||||
// as returned by dataSourceInterfaceSchemaMake()
|
// as returned by dataSourceInterfaceSchemaMake()
|
||||||
elem[" attribute "] = value. attribute
|
elem["net_id"] = value.NetId
|
||||||
...
|
elem["net_type"] = value.NetType
|
||||||
|
elem["ip_address"] = value.IPAddress
|
||||||
|
elem["netmask"] = value.NetMask
|
||||||
|
elem["mac"] = value.MAC
|
||||||
|
elem["default_gw"] = value.DefaultGW
|
||||||
|
elem["name"] = value.Name
|
||||||
|
elem["connection_id"] = value.ConnID
|
||||||
|
elem["connection_type"] = value.ConnType
|
||||||
|
|
||||||
|
qos_schema := interfaceQosSubresourceSchemaMake()
|
||||||
|
qos_schema.Set("egress_rate", value.QOS.ERate)
|
||||||
|
qos_schema.Set("ingress_rate", value.QOS.InRate)
|
||||||
|
qos_schema.Set("ingress_burst", value.QOS.InBurst)
|
||||||
|
elem["qos"] = qos_schema
|
||||||
|
|
||||||
result[i] = elem
|
result[i] = elem
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +119,7 @@ func flattenCompute(d *schema.ResourceData, comp_facts string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("flattenCompute: model.ID %d, model.ResGroupID %d", model.ID, model.ResGroupID)
|
log.Debugf("flattenCompute: ID %d, ResGroupID %d", model.ID, model.ResGroupID)
|
||||||
|
|
||||||
d.SetId(fmt.Sprintf("%d", model.ID))
|
d.SetId(fmt.Sprintf("%d", model.ID))
|
||||||
d.Set("compute_id", model.ID)
|
d.Set("compute_id", model.ID)
|
||||||
@@ -119,25 +145,15 @@ func flattenCompute(d *schema.ResourceData, comp_facts string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(model.Interfaces) > 0 {
|
if len(model.Interfaces) > 0 {
|
||||||
log.Printf("flattenCompute: calling parseComputeInterfaces for %d interfaces", len(model.Interfaces))
|
log.Debugf("flattenCompute: calling parseComputeInterfaces for %d interfaces", len(model.Interfaces))
|
||||||
if err = d.Set("interfaces", parseComputeInterfaces(model.Interfaces)); err != nil {
|
if err = d.Set("interfaces", parseComputeInterfaces(model.Interfaces)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(model.GuestLogins) > 0 {
|
if len(model.GuestLogins) > 0 {
|
||||||
log.Printf("flattenCompute: calling parseGuestLogins")
|
log.Debugf("flattenCompute: calling parseGuestLogins for %d logins", len(model.GuestLogins))
|
||||||
guest_logins := parseGuestLogins(model.GuestLogins)
|
if err = d.Set("guest_logins", parseGuestLogins(model.GuestLogins)); err != nil {
|
||||||
if err = d.Set("guest_logins", guest_logins); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
default_login := guest_logins[0].(map[string]interface{})
|
|
||||||
// set user & password attributes to the corresponding values of the 1st item in the list
|
|
||||||
if err = d.Set("user", default_login["login"]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = d.Set("password", default_login["password"]); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,7 +279,7 @@ func dataSourceCompute() *schema.Resource {
|
|||||||
Type: schema.TypeList,
|
Type: schema.TypeList,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Elem: &schema.Resource {
|
Elem: &schema.Resource {
|
||||||
Schema: interfaceSubresourceSchema(),
|
Schema: interfaceSubresourceSchemaMake(),
|
||||||
},
|
},
|
||||||
Description: "Specification for the virtual NICs configured on this compute instance.",
|
Description: "Specification for the virtual NICs configured on this compute instance.",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -74,15 +74,14 @@ func utilityDiskCheckPresence(d *schema.ResourceData, m interface{}) (string, er
|
|||||||
return "", fmt.Error("Cannot locate disk if name is empty and no disk ID specified.")
|
return "", fmt.Error("Cannot locate disk if name is empty and no disk ID specified.")
|
||||||
}
|
}
|
||||||
|
|
||||||
account_id, acc_id_set := d.GetOk("account_id")
|
// Valid account ID is required to locate disks
|
||||||
if !acc_id_set {
|
// obtain Account ID by account name - it should not be zero on success
|
||||||
account_name, arg_set := d.GetOkd("account_name")
|
validated_account_id, err := utilityGetAccountIdBySchema(d, m)
|
||||||
if !arg_set {
|
if err != nil {
|
||||||
return "", fmt.Error("Cannot locate disk by name %s if neither account ID nor account name are set", disk_name.(string))
|
return err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
url_values.Add("accountId", fmt.Sprintf("%d", account_id.(int)))
|
url_values.Add("accountId", fmt.Sprintf("%d", validated_account_id))
|
||||||
disk_facts, err := controller.decortAPICall("POST", DisksListAPI, url_values)
|
disk_facts, err := controller.decortAPICall("POST", DisksListAPI, url_values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -100,7 +99,7 @@ func utilityDiskCheckPresence(d *schema.ResourceData, m interface{}) (string, er
|
|||||||
log.Debugf("utilityDiskCheckPresence: traversing decoded JSON of length %d", len(disks_list))
|
log.Debugf("utilityDiskCheckPresence: traversing decoded JSON of length %d", len(disks_list))
|
||||||
for _, item := range disks_list {
|
for _, item := range disks_list {
|
||||||
// need to match disk by name, return the first match
|
// need to match disk by name, return the first match
|
||||||
if item.Name == disk_name && item.Status != "DESTROYED" {
|
if item.Name == disk_name.(string) && item.Status != "DESTROYED" {
|
||||||
log.Printf("utilityDiskCheckPresence: index %d, matched disk name %q", index, item.Name)
|
log.Printf("utilityDiskCheckPresence: index %d, matched disk name %q", index, item.Name)
|
||||||
// we found the disk we need - not get detailed information via API call to disks/get
|
// we found the disk we need - not get detailed information via API call to disks/get
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2019-2020 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -16,10 +16,10 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
Technology platfom.
|
Technology platfom.
|
||||||
|
|
||||||
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package decort
|
package decort
|
||||||
@@ -34,39 +34,41 @@ import (
|
|||||||
"github.com/hashicorp/terraform/helper/validation"
|
"github.com/hashicorp/terraform/helper/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
|
func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
|
||||||
name := d.Get("name").(string)
|
name := d.Get("name").(string)
|
||||||
rgid, rgid_set := d.GetOk("rgid")
|
// rg_id, rgid_set := d.GetOk("rg_id")
|
||||||
tenant_id, tenant_set := d.GetOk("tenant_id")
|
account_id, account_set := d.GetOk("account_id")
|
||||||
|
|
||||||
controller := m.(*ControllerCfg)
|
controller := m.(*ControllerCfg)
|
||||||
url_values := &url.Values{}
|
url_values := &url.Values{}
|
||||||
if tenant_set {
|
if account_set {
|
||||||
url_values.Add("accountId", fmt.Sprintf("%d",tenant_id.(int)))
|
url_values.Add("accountId", fmt.Sprintf("%d", account_id.(int)))
|
||||||
}
|
|
||||||
if rgid_set {
|
|
||||||
url_values.Add("cloudspaceId", fmt.Sprintf("%d",rgid.(int)))
|
|
||||||
}
|
}
|
||||||
body_string, err := controller.decortAPICall("POST", ImagesListAPI, url_values)
|
body_string, err := controller.decortAPICall("POST", ImagesListAPI, url_values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("dataSourceImageRead: ready to decode response body")
|
log.Debugf("dataSourceImageRead: ready to decode response body from %q", ImagesListAPI)
|
||||||
model := ImagesListResp{}
|
model := ImagesListResp{}
|
||||||
err = json.Unmarshal([]byte(body_string), &model)
|
err = json.Unmarshal([]byte(body_string), &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("%#v", model)
|
// log.Printf("%#v", model)
|
||||||
log.Printf("dataSourceImageRead: traversing decoded JSON of length %d", len(model))
|
log.Debugf("dataSourceImageRead: traversing decoded JSON of length %d", len(model))
|
||||||
for index, item := range model {
|
for index, item := range model {
|
||||||
// need to match VM by name
|
// need to match Image by name
|
||||||
if item.Name == name {
|
if item.Name == name {
|
||||||
log.Printf("dataSourceImageRead: index %d, matched name %q", index, item.Name)
|
log.Printf("dataSourceImageRead: index %d, matched name %q", index, item.Name)
|
||||||
d.SetId(fmt.Sprintf("%d", model[index].ID))
|
d.SetId(fmt.Sprintf("%d", item.ID))
|
||||||
|
d.Set("account_id", item.AccountID)
|
||||||
|
d.Set("arch", item.Arch)
|
||||||
|
d.Set("sep_id", item.SepID)
|
||||||
|
d.Set("pool", item.Pool)
|
||||||
|
d.Set("status", item.Status)
|
||||||
|
d.Set("size", item.Size)
|
||||||
// d.Set("field_name", value)
|
// d.Set("field_name", value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -76,36 +78,67 @@ func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dataSourceImage() *schema.Resource {
|
func dataSourceImage() *schema.Resource {
|
||||||
return &schema.Resource {
|
return &schema.Resource{
|
||||||
SchemaVersion: 1,
|
SchemaVersion: 1,
|
||||||
|
|
||||||
Read: dataSourceImageRead,
|
Read: dataSourceImageRead,
|
||||||
|
|
||||||
Timeouts: &schema.ResourceTimeout {
|
Timeouts: &schema.ResourceTimeout{
|
||||||
Read: &Timeout30s,
|
Read: &Timeout30s,
|
||||||
Default: &Timeout60s,
|
Default: &Timeout60s,
|
||||||
},
|
},
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema {
|
Schema: map[string]*schema.Schema{
|
||||||
"name": {
|
"name": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
Description: "Name of the OS image to locate. This parameter is case sensitive.",
|
Description: "Name of the OS image to locate. This parameter is case sensitive.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"tenant_id": {
|
"account_id": {
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
ValidateFunc: validation.IntAtLeast(1),
|
ValidateFunc: validation.IntAtLeast(1),
|
||||||
Description: "ID of the tenant to limit image search to.",
|
Description: "Optional ID of the account to limit image search to.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"rgid": {
|
"arch": {
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Computed: true,
|
||||||
ValidateFunc: validation.IntAtLeast(1),
|
Description: "Binary architecture this image is created for.",
|
||||||
Description: "ID of the resource group to limit image search to.",
|
},
|
||||||
|
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Storage end-point provider serving this image.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
"sep_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of the storage end-point provider serving this image.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"pool": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Pool where this image is located.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Size of the image in GB.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Current model status of this disk.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
330
decort/interface_subresource.go
Normal file
330
decort/interface_subresource.go
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file contains definitions and code for handling Interface component of Compute schema
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interfaceSubresourceSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"net_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the network entity this interface is connected to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"net_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of the network entity this interface is connected to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ip_address": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "IP addresses assigned to this interface.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"netmask": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Network mask to be used with this interface.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"mac": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "MAC address of this interface.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"default_gw": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Default gateway associated with this interface.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Interface name.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"connection_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "VxLAN or VLAN ID this interface is connected to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"connection_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of the segment (VLAN or VxLAN) this interface is connected to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"qos": {
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: interfaceQosSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Details about the guest OS users provisioned together with this compute instance.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func interfaceQosSubresourceSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"egress_rate": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Egress rate limit on this interface.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ingress_burst": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Ingress burst limit on this interface.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ingress_rate": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Ingress rate limit on this interface.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "GUID of this QoS record.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func flattenNetworks(nets []NicRecord) []interface{} {
|
||||||
|
// this function expects an array of NicRecord as returned by machines/get API call
|
||||||
|
// NOTE: it does NOT expect a strucutre as returned by externalnetwork/list
|
||||||
|
var length = 0
|
||||||
|
var strarray []string
|
||||||
|
|
||||||
|
for _, value := range nets {
|
||||||
|
if value.NicType == "PUBLIC" {
|
||||||
|
length += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("flattenNetworks: found %d NICs with PUBLIC type", length)
|
||||||
|
|
||||||
|
result := make([]interface{}, length)
|
||||||
|
if length == 0 {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
elem := make(map[string]interface{})
|
||||||
|
|
||||||
|
var subindex = 0
|
||||||
|
for index, value := range nets {
|
||||||
|
if value.NicType == "PUBLIC" {
|
||||||
|
// this will be changed as network segments entity
|
||||||
|
// value.Params for ext net comes in a form "gateway:176.118.165.1 externalnetworkId:6"
|
||||||
|
// for network_id we need to extract from this string
|
||||||
|
strarray = strings.Split(value.Params, " ")
|
||||||
|
substr := strings.Split(strarray[1], ":")
|
||||||
|
elem["network_id"], _ = strconv.Atoi(substr[1])
|
||||||
|
elem["ip_range"] = value.IPAddress
|
||||||
|
// elem["label"] = ... - should be uncommented for the future release
|
||||||
|
log.Printf("flattenNetworks: parsed element %d - network_id %d, ip_range %q",
|
||||||
|
index, elem["network_id"].(int), value.IPAddress)
|
||||||
|
result[subindex] = elem
|
||||||
|
subindex += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func makePortforwardsConfig(arg_list []interface{}) (pfws []PortforwardConfig, count int) {
|
||||||
|
count = len(arg_list)
|
||||||
|
if count < 1 {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pfws = make([]PortforwardConfig, count)
|
||||||
|
var subres_data map[string]interface{}
|
||||||
|
for index, value := range arg_list {
|
||||||
|
subres_data = value.(map[string]interface{})
|
||||||
|
// pfws[index].Label = subres_data["label"].(string) - should be uncommented for future release
|
||||||
|
pfws[index].ExtPort = subres_data["ext_port"].(int)
|
||||||
|
pfws[index].IntPort = subres_data["int_port"].(int)
|
||||||
|
pfws[index].Proto = subres_data["proto"].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pfws, count
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenPortforwards(pfws []PortforwardRecord) []interface{} {
|
||||||
|
result := make([]interface{}, len(pfws))
|
||||||
|
elem := make(map[string]interface{})
|
||||||
|
var port_num int
|
||||||
|
|
||||||
|
for index, value := range pfws {
|
||||||
|
// elem["label"] = ... - should be uncommented for the future release
|
||||||
|
|
||||||
|
// external port field is of TypeInt in the portforwardSubresourceSchema, but string is returned
|
||||||
|
// by portforwards/list API, so we need conversion here
|
||||||
|
port_num, _ = strconv.Atoi(value.ExtPort)
|
||||||
|
elem["ext_port"] = port_num
|
||||||
|
// internal port field is of TypeInt in the portforwardSubresourceSchema, but string is returned
|
||||||
|
// by portforwards/list API, so we need conversion here
|
||||||
|
port_num, _ = strconv.Atoi(value.IntPort)
|
||||||
|
elem["int_port"] = port_num
|
||||||
|
elem["proto"] = value.Proto
|
||||||
|
elem["ext_ip"] = value.ExtIP
|
||||||
|
elem["int_ip"] = value.IntIP
|
||||||
|
result[index] = elem
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func portforwardSubresourceSchema() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
/* this should be uncommented for the future release
|
||||||
|
"label": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Unique label of this network connection to identify it amnong other connections for this VM.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"ext_port": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, 65535),
|
||||||
|
Description: "External port number for this port forwarding rule.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"int_port": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, 65535),
|
||||||
|
Description: "Internal port number for this port forwarding rule.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"proto": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
// ValidateFunc: validation.IntBetween(1, ),
|
||||||
|
Description: "Protocol type for this port forwarding rule. Should be either 'tcp' or 'udp'.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ext_ip": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: ".",
|
||||||
|
},
|
||||||
|
|
||||||
|
"int_ip": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: ".",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenNICs(nics []NicRecord) []interface{} {
|
||||||
|
var result = make([]interface{}, len(nics))
|
||||||
|
elem := make(map[string]interface{})
|
||||||
|
|
||||||
|
for index, value := range nics {
|
||||||
|
elem["status"] = value.Status
|
||||||
|
elem["type"] = value.NicType
|
||||||
|
elem["mac"] = value.MacAddress
|
||||||
|
elem["ip_address"] = value.IPAddress
|
||||||
|
elem["parameters"] = value.Params
|
||||||
|
elem["reference_id"] = value.ReferenceID
|
||||||
|
elem["network_id"] = value.NetworkID
|
||||||
|
result[index] = elem
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func nicSubresourceSchema() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Current status of this NIC.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of this NIC.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"mac": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "MAC address assigned to this NIC.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ip_address": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "IP address assigned to this NIC.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"parameters": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Additional NIC parameters.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Reference ID of this NIC.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"network_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Network ID which this NIC is connected to.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -15,17 +15,16 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package decs
|
package decort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
// "github.com/hashicorp/terraform/helper/validation"
|
// "github.com/hashicorp/terraform/helper/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
func flattenGuestLogins(logins []GuestLoginRecord) []interface{} {
|
func parseGuestLogins(logins []OsUserRecord) []interface{} {
|
||||||
var result = make([]interface{}, len(logins))
|
var result = make([]interface{}, len(logins))
|
||||||
|
|
||||||
elem := make(map[string]interface{})
|
elem := make(map[string]interface{})
|
||||||
@@ -34,28 +33,28 @@ func flattenGuestLogins(logins []GuestLoginRecord) []interface{} {
|
|||||||
elem["guid"] = value.Guid
|
elem["guid"] = value.Guid
|
||||||
elem["login"] = value.Login
|
elem["login"] = value.Login
|
||||||
elem["password"] = value.Password
|
elem["password"] = value.Password
|
||||||
|
elem["public_key"] = value.PubKey
|
||||||
result[index] = elem
|
result[index] = elem
|
||||||
log.Printf("flattenGuestLogins: parsed element %d - login %q",
|
log.Debugf("parseGuestLogins: parsed element %d - login %q", index, value.Login)
|
||||||
index, value.Login)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func loginsSubresourceSchema() map[string]*schema.Schema {
|
func loginsSubresourceSchemaMake() map[string]*schema.Schema {
|
||||||
rets := map[string]*schema.Schema {
|
rets := map[string]*schema.Schema{
|
||||||
"guid": {
|
"guid": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Default: "",
|
Default: "",
|
||||||
Description: "GUID of this guest user.",
|
Description: "GUID of this guest OS user.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"login": {
|
"login": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Default: "",
|
Default: "",
|
||||||
Description: "Login name of this guest user.",
|
Description: "Login name of this guest OS user.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"password": {
|
"password": {
|
||||||
@@ -63,7 +62,14 @@ func loginsSubresourceSchema() map[string]*schema.Schema {
|
|||||||
Optional: true,
|
Optional: true,
|
||||||
Default: "",
|
Default: "",
|
||||||
Sensitive: true,
|
Sensitive: true,
|
||||||
Description: "Password of this guest user.",
|
Description: "Password of this guest OS user.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"public_key": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "",
|
||||||
|
Description: "SSH public key of this guest user.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,17 +16,15 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
Technology platfom.
|
Technology platfom.
|
||||||
|
|
||||||
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package decort
|
package decort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,157 +38,163 @@ var Timeout180s = time.Second * 180
|
|||||||
// structures related to /cloudapi/rg/list API
|
// structures related to /cloudapi/rg/list API
|
||||||
//
|
//
|
||||||
type UserAclRecord struct {
|
type UserAclRecord struct {
|
||||||
IsExplicit bool `json:"explicit"`
|
IsExplicit bool `json:"explicit"`
|
||||||
Rights string `json:"right"`
|
Rights string `json:"right"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
UgroupID string `json:"userGroupId"`
|
UgroupID string `json:"userGroupId"`
|
||||||
// CanBeDeleted bool `json:"canBeDeleted"`
|
// CanBeDeleted bool `json:"canBeDeleted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccountAclRecord struct {
|
type AccountAclRecord struct {
|
||||||
IsExplicit bool `json:"explicit"`
|
IsExplicit bool `json:"explicit"`
|
||||||
Guid string `json:"guid"`
|
Guid string `json:"guid"`
|
||||||
Rights string `json:"right"`
|
Rights string `json:"right"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
UgroupID string `json:"userGroupId"`
|
UgroupID string `json:"userGroupId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResgroupRecord struct {
|
type ResgroupRecord struct {
|
||||||
ACLs []UserAclRecord `json:"ACLs"`
|
ACLs []UserAclRecord `json:"ACLs"`
|
||||||
Owner AccountAclRecord `json:"accountAcl"`
|
Owner AccountAclRecord `json:"accountAcl"`
|
||||||
AccountID int `json:"accountId"`
|
AccountID int `json:"accountId"`
|
||||||
AccountName string `json:"accountName"`
|
AccountName string `json:"accountName"`
|
||||||
CreatedBy string `json:"createdBy"`
|
CreatedBy string `json:"createdBy"`
|
||||||
CreatedTime uint64 `json:"createdTime"`
|
CreatedTime uint64 `json:"createdTime"`
|
||||||
DefaultNetID int `json:"def_net_id"`
|
DefaultNetID int `json:"def_net_id"`
|
||||||
DefaultNetType string `json:"def_net_type"`
|
DefaultNetType string `json:"def_net_type"`
|
||||||
Decsription string `json:"desc"`
|
Decsription string `json:"desc"`
|
||||||
GridID int `json:"gid"`
|
GridID int `json:"gid"`
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
LockStatus string `json:"lockStatus"`
|
LockStatus string `json:"lockStatus"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
UpdatedBy string `json:"updatedBy"`
|
UpdatedBy string `json:"updatedBy"`
|
||||||
UpdatedTime uint64 `json:"updatedTime"`
|
UpdatedTime uint64 `json:"updatedTime"`
|
||||||
Vins []int `json:"vins"`
|
Vins []int `json:"vins"`
|
||||||
Computes []int `json:"vms"`
|
Computes []int `json:"vms"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ResgroupListAPI = "/restmachine/cloudapi/rg/list"
|
const ResgroupListAPI = "/restmachine/cloudapi/rg/list"
|
||||||
|
|
||||||
type ResgroupListResp []ResgroupRecord
|
type ResgroupListResp []ResgroupRecord
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/rg/create API call
|
// structures related to /cloudapi/rg/create API call
|
||||||
//
|
//
|
||||||
const ResgroupCreateAPI= "/restmachine/cloudapi/rg/create"
|
const ResgroupCreateAPI = "/restmachine/cloudapi/rg/create"
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/rg/update API call
|
// structures related to /cloudapi/rg/update API call
|
||||||
//
|
//
|
||||||
const ResgroupUpdateAPI= "/restmachine/cloudapi/rg/update"
|
const ResgroupUpdateAPI = "/restmachine/cloudapi/rg/update"
|
||||||
|
|
||||||
type ResgroupUpdateParam struct {
|
type ResgroupUpdateParam struct {
|
||||||
RgId int `json:"rgId"`
|
RgId int `json:"rgId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Desc string `json:"decs"`
|
Desc string `json:"decs"`
|
||||||
Ram int `json:"maxMemoryCapacity"`
|
Ram int `json:"maxMemoryCapacity"`
|
||||||
Disk int `json:"maxVDiskCapacity"`
|
Disk int `json:"maxVDiskCapacity"`
|
||||||
Cpu int `json:"maxCPUCapacity"`
|
Cpu int `json:"maxCPUCapacity"`
|
||||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||||
Reason string `json:"reason"`
|
Reason string `json:"reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/rg/get API call
|
// structures related to /cloudapi/rg/get API call
|
||||||
//
|
//
|
||||||
type QuotaRecord struct { // this is how quota is reported by /api/.../rg/get
|
type QuotaRecord struct { // this is how quota is reported by /api/.../rg/get
|
||||||
Cpu int `json:"CU_C"` // CPU count in pcs
|
Cpu int `json:"CU_C"` // CPU count in pcs
|
||||||
Ram int `json:"CU_M"` // RAM volume in MB
|
Ram int `json:"CU_M"` // RAM volume in MB
|
||||||
Disk int `json:"CU_D"` // Disk capacity in GB
|
Disk int `json:"CU_D"` // Disk capacity in GB
|
||||||
ExtIPs int `json:"CU_I"` // Ext IPs count
|
ExtIPs int `json:"CU_I"` // Ext IPs count
|
||||||
ExtTraffic int `json:"CU_NP"` // Ext network traffic
|
ExtTraffic int `json:"CU_NP"` // Ext network traffic
|
||||||
GpuUnits int `json:"gpu_units"` // GPU count
|
GpuUnits int `json:"gpu_units"` // GPU count
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResourceRecord struct { // this is how actual usage is reported by /api/.../rg/get
|
type ResourceRecord struct { // this is how actual usage is reported by /api/.../rg/get
|
||||||
Cpu int `json:"cpu"`
|
Cpu int `json:"cpu"`
|
||||||
Disk int `json:"disksize"`
|
Disk int `json:"disksize"`
|
||||||
ExtIPs int `json:"extips"`
|
ExtIPs int `json:"extips"`
|
||||||
ExtTraffic int `json:"exttraffic"`
|
ExtTraffic int `json:"exttraffic"`
|
||||||
Gpu int `json:"gpu"`
|
Gpu int `json:"gpu"`
|
||||||
Ram int `json:"ram"`
|
Ram int `json:"ram"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UsageRecord struct {
|
type UsageRecord struct {
|
||||||
Current ResourceRecord `json:"Current"`
|
Current ResourceRecord `json:"Current"`
|
||||||
Reserved ResourceRecord `json:"Reserved"`
|
Reserved ResourceRecord `json:"Reserved"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ResgroupGetAPI= "/restmachine/cloudapi/rg/get"
|
const ResgroupGetAPI = "/restmachine/cloudapi/rg/get"
|
||||||
type ResgroupGetResp struct {
|
|
||||||
ACLs []UserAclRecord `json:"ACLs"`
|
|
||||||
Usage UsageRecord `json:"Resources"`
|
|
||||||
AccountID int `json:"accountId"`
|
|
||||||
AccountName string `json:"accountName"`
|
|
||||||
|
|
||||||
CreatedBy string `json:"createdBy"`
|
type ResgroupGetResp struct {
|
||||||
CreatedTime uint64 `json:"createdTime"`
|
ACLs []UserAclRecord `json:"ACLs"`
|
||||||
DefaultNetID int `json:"def_net_id"`
|
Usage UsageRecord `json:"Resources"`
|
||||||
DefaultNetType string `json:"def_net_type"`
|
AccountID int `json:"accountId"`
|
||||||
DeletedBy string `json:"deletedBy"`
|
AccountName string `json:"accountName"`
|
||||||
DeletedTime uint64 `json:"deletedTime"`
|
|
||||||
Decsription string `json:"desc"`
|
CreatedBy string `json:"createdBy"`
|
||||||
ID uint `json:"id"`
|
CreatedTime uint64 `json:"createdTime"`
|
||||||
LockStatus string `json:"lockStatus"`
|
DefaultNetID int `json:"def_net_id"`
|
||||||
Name string `json:"name"`
|
DefaultNetType string `json:"def_net_type"`
|
||||||
Quota QuotaRecord `json:"resourceLimits"`
|
DeletedBy string `json:"deletedBy"`
|
||||||
Status string `json:"status"`
|
DeletedTime uint64 `json:"deletedTime"`
|
||||||
UpdatedBy string `json:"updatedBy"`
|
Decsription string `json:"desc"`
|
||||||
UpdatedTime uint64 `json:"updatedTime"`
|
ID uint `json:"id"`
|
||||||
Vins []int `json:"vins"`
|
LockStatus string `json:"lockStatus"`
|
||||||
Computes []int `json:"vms"`
|
Name string `json:"name"`
|
||||||
|
Quota QuotaRecord `json:"resourceLimits"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
UpdatedBy string `json:"updatedBy"`
|
||||||
|
UpdatedTime uint64 `json:"updatedTime"`
|
||||||
|
Vins []int `json:"vins"`
|
||||||
|
Computes []int `json:"vms"`
|
||||||
|
|
||||||
Ignored map[string]interface{} `json:"-"`
|
Ignored map[string]interface{} `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/rg/update API
|
// structures related to /cloudapi/rg/update API
|
||||||
//
|
//
|
||||||
const ResgroupUpdateAPI = "/restmachine/cloudapi/rg/update"
|
const ResgroupUpdateAPI = "/restmachine/cloudapi/rg/update"
|
||||||
|
|
||||||
type ResgroupUpdateParam struct {
|
type ResgroupUpdateParam struct {
|
||||||
ID uint `json:"rgId"`
|
ID uint `json:"rgId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Decsription string `json:"desc"`
|
Decsription string `json:"desc"`
|
||||||
Cpu int `json:"maxCPUCapacity"`
|
Cpu int `json:"maxCPUCapacity"`
|
||||||
Ram int `json:"maxMemoryCapacity"`
|
Ram int `json:"maxMemoryCapacity"`
|
||||||
Disk int `json:"maxVDiskCapacity"`
|
Disk int `json:"maxVDiskCapacity"`
|
||||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||||
ExtIPs int `json:"maxNumPublicIP"`
|
ExtIPs int `json:"maxNumPublicIP"`
|
||||||
Reason string `json:"reason"`
|
Reason string `json:"reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/rg/delete API
|
// structures related to /cloudapi/rg/delete API
|
||||||
//
|
//
|
||||||
const ResgroupDeleteAPI = "/restmachine/cloudapi/rg/delete"
|
const ResgroupDeleteAPI = "/restmachine/cloudapi/rg/delete"
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/rg/listComputes API
|
// structures related to /cloudapi/rg/listComputes API
|
||||||
//
|
//
|
||||||
type ComputeBriefRecord struct { // this is a brief compute specifiaction as returned by API rg/listComputes
|
type ComputeBriefRecord struct { // this is a brief compute specifiaction as returned by API rg/listComputes
|
||||||
// we do not even include here all fields as returned by this API, but only the most important that
|
// we do not even include here all fields as returned by this API, but only the most important that
|
||||||
// are really necessary to identify and distinguish computes
|
// are really necessary to identify and distinguish computes
|
||||||
AccountID int `json:"accountId"`
|
AccountID int `json:"accountId"`
|
||||||
AccountName string `json:"accountName"`
|
AccountName string `json:"accountName"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
RgID int `json:"rgId"`
|
RgID int `json:"rgId"`
|
||||||
RgName string `json:"rgName"`
|
RgName string `json:"rgName"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
TechStatus string `json:"techStatus"`
|
TechStatus string `json:"techStatus"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const RgListComputesAPI = "/restmachine/cloudapi/rg/listComputes"
|
const RgListComputesAPI = "/restmachine/cloudapi/rg/listComputes"
|
||||||
|
|
||||||
type RgListComputesResp []ComputeBriefRecord
|
type RgListComputesResp []ComputeBriefRecord
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -198,339 +202,315 @@ type RgListComputesResp []ComputeBriefRecord
|
|||||||
//
|
//
|
||||||
const KvmX86CreateAPI = "/restmachine/cloudapi/kvmx86/create"
|
const KvmX86CreateAPI = "/restmachine/cloudapi/kvmx86/create"
|
||||||
const KvmPPCCreateAPI = "/restmachine/cloudapi/kvmppc/create"
|
const KvmPPCCreateAPI = "/restmachine/cloudapi/kvmppc/create"
|
||||||
|
|
||||||
type KvmVmCreateParam struct { // this is unified structure for both x86 and PPC based KVM VMs creation
|
type KvmVmCreateParam struct { // this is unified structure for both x86 and PPC based KVM VMs creation
|
||||||
RgID uint `json:"rgId"`
|
RgID uint `json:"rgId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Cpu int `json:"cpu"`
|
Cpu int `json:"cpu"`
|
||||||
Ram int `json:"ram"`
|
Ram int `json:"ram"`
|
||||||
ImageID int `json:"imageId"`
|
ImageID int `json:"imageId"`
|
||||||
BootDisk int `json:"bootDisk"`
|
BootDisk int `json:"bootDisk"`
|
||||||
NetType string `json:"netType"`
|
NetType string `json:"netType"`
|
||||||
NetId int `json:"netId"`
|
NetId int `json:"netId"`
|
||||||
IPAddr string `json:"ipAddr"`
|
IPAddr string `json:"ipAddr"`
|
||||||
UserData string `json:"userdata"`
|
UserData string `json:"userdata"`
|
||||||
Description string `json:"desc"`
|
Description string `json:"desc"`
|
||||||
Start bool `json:"start"`
|
Start bool `json:"start"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// structures related to cloudapi/compute/delete API
|
// structures related to cloudapi/compute/delete API
|
||||||
const ComputeDeleteAPI = "/restmachine/cloudapi/compute/delete"
|
const ComputeDeleteAPI = "/restmachine/cloudapi/compute/delete"
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/compute/list API
|
// structures related to /cloudapi/compute/list API
|
||||||
//
|
//
|
||||||
|
|
||||||
|
type InterfaceQosRecord struct {
|
||||||
|
ERate int `json:"eRate"`
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
InBurst int `json:"inBurst"`
|
||||||
|
InRate int `json:"inRate"`
|
||||||
|
}
|
||||||
|
|
||||||
type InterfaceRecord struct {
|
type InterfaceRecord struct {
|
||||||
ConnID int `json:"connId"`
|
ConnID int `json:"connId"` // This is VLAN ID or VxLAN ID, depending on ConnType
|
||||||
ConnType string `json:"connType"`
|
ConnType string `json:"connType"` // Either "VLAN" or "VXLAN" tag
|
||||||
DefaultGW string `json:"defGw"`
|
DefaultGW string `json:"defGw"`
|
||||||
Guid string `json:"guid"`
|
Guid string `json:"guid"`
|
||||||
IPAddress string `json:"ipAddress"` // without trailing network mask, i.e. "192.168.1.3"
|
IPAddress string `json:"ipAddress"` // without trailing network mask, i.e. "192.168.1.3"
|
||||||
MAC string `json:"mac"`
|
MAC string `json:"mac"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
NetID int `json:"netId"`
|
NetID int `json:"netId"` // This is either ExtNet ID or ViNS ID, depending on NetType
|
||||||
NetMaks int `json:"netMask"`
|
NetMask int `json:"netMask"`
|
||||||
NetType string `json:"netType"`
|
NetType string `json:"netType"` // Either "EXTNET" or "VINS" tag
|
||||||
PciSlot int `json:"pciSlot"`
|
PciSlot int `json:"pciSlot"`
|
||||||
Target string `json:"target"`
|
Target string `json:"target"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
VNFs []int `json:"vnfs"`
|
VNFs []int `json:"vnfs"`
|
||||||
|
QOS InterfaceQosRecord `json:"qos"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SnapSetRecord struct {
|
type SnapSetRecord struct {
|
||||||
Disks []int `json:"disks"`
|
Disks []int `json:"disks"`
|
||||||
Guid string `json:"guid"`
|
Guid string `json:"guid"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
TimeStamp uint64 `json:"timestamp"`
|
TimeStamp uint64 `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComputeRecord struct {
|
type ComputeRecord struct {
|
||||||
AccountID int `json:"accountId"`
|
AccountID int `json:"accountId"`
|
||||||
AccountName string `json:"accountName"`
|
AccountName string `json:"accountName"`
|
||||||
ACLs []UserAclRecord `json:"acl"`
|
ACLs []UserAclRecord `json:"acl"`
|
||||||
Arch string `json:"arch"`
|
Arch string `json:"arch"`
|
||||||
BootDiskSize int `json:"bootdiskSize"`
|
BootDiskSize int `json:"bootdiskSize"`
|
||||||
CloneReference int `json:"cloneReference"`
|
CloneReference int `json:"cloneReference"`
|
||||||
Clones []int `json:"clones"`
|
Clones []int `json:"clones"`
|
||||||
Cpus int `json:"cpus"`
|
Cpus int `json:"cpus"`
|
||||||
CreatedBy string `json:"createdBy"`
|
CreatedBy string `json:"createdBy"`
|
||||||
CreatedTime uint64 `json:"createdTime"`
|
CreatedTime uint64 `json:"createdTime"`
|
||||||
DeletedBy string `json:"deletedBy"`
|
DeletedBy string `json:"deletedBy"`
|
||||||
DeletedTime uint64 `json:"deletedTime"`
|
DeletedTime uint64 `json:"deletedTime"`
|
||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
Disks []int `json:"disks"`
|
Disks []int `json:"disks"`
|
||||||
GridID int `json:"gid"`
|
GridID int `json:"gid"`
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
ImageID int `json:"imageId"`
|
ImageID int `json:"imageId"`
|
||||||
Interfaces []InterfaceRecord `json:"interfaces`
|
Interfaces []InterfaceRecord `json:"interfaces`
|
||||||
LockStatus string `json:"lockStatus"`
|
LockStatus string `json:"lockStatus"`
|
||||||
ManagerID int `json:"managerId"`
|
ManagerID int `json:"managerId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Ram int `json:"ram"`
|
Ram int `json:"ram"`
|
||||||
RgID int `json:"rgId"`
|
RgID int `json:"rgId"`
|
||||||
RgName string `json:"rgName"`
|
RgName string `json:"rgName"`
|
||||||
SnapSets []SnapSetRecord `json:"snapSets"`
|
SnapSets []SnapSetRecord `json:"snapSets"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Tags []string `json:"tags"`
|
Tags []string `json:"tags"`
|
||||||
TechStatus string `json:"techStatus"`
|
TechStatus string `json:"techStatus"`
|
||||||
TotalDiskSize int `json:"totalDiskSize"`
|
TotalDiskSize int `json:"totalDiskSize"`
|
||||||
UpdatedBy string `json:"updatedBy"`
|
UpdatedBy string `json:"updatedBy"`
|
||||||
UpdateTime uint64 `json:"updateTime"`
|
UpdateTime uint64 `json:"updateTime"`
|
||||||
UserManaged bool `json:"userManaged"`
|
UserManaged bool `json:"userManaged"`
|
||||||
Vgpus []int `json:"vgpus"`
|
Vgpus []int `json:"vgpus"`
|
||||||
VinsConnected int `json:"vinsConnected"`
|
VinsConnected int `json:"vinsConnected"`
|
||||||
VirtualImageID int `json:"virtualImageId"`
|
VirtualImageID int `json:"virtualImageId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComputeListAPI = "/restmachine/cloudapi/compute/list"
|
const ComputeListAPI = "/restmachine/cloudapi/compute/list"
|
||||||
|
|
||||||
type ComputeListResp []ComputeRecord
|
type ComputeListResp []ComputeRecord
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/compute/get
|
// structures related to /cloudapi/compute/get
|
||||||
//
|
//
|
||||||
type SnapshotRecord struct {
|
type SnapshotRecord struct {
|
||||||
Guid string `json:"guid"`
|
Guid string `json:"guid"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
SnapSetGuid string `json:"snapSetGuid"`
|
SnapSetGuid string `json:"snapSetGuid"`
|
||||||
SnapSetTime uint64 `json:"snapSetTime"`
|
SnapSetTime uint64 `json:"snapSetTime"`
|
||||||
TimeStamp uint64 `json:"timestamp"`
|
TimeStamp uint64 `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiskRecord struct {
|
type DiskRecord struct {
|
||||||
// ACLs `json:"ACL"` - it is a dictionary, special parsing required
|
// ACLs `json:"ACL"` - it is a dictionary, special parsing required
|
||||||
// was - Acl map[string]string `json:"acl"`
|
// was - Acl map[string]string `json:"acl"`
|
||||||
AccountID int `json:"accountId"`
|
AccountID int `json:"accountId"`
|
||||||
AccountName string `json:"accountName"` // NOTE: absent from compute/get output
|
AccountName string `json:"accountName"` // NOTE: absent from compute/get output
|
||||||
BootPartition int `json:"bootPartition"`
|
BootPartition int `json:"bootPartition"`
|
||||||
CreatedTime uint64 `json:"creationTime"`
|
CreatedTime uint64 `json:"creationTime"`
|
||||||
DeletedTime uint64 `json:"deletionTime"`
|
DeletedTime uint64 `json:"deletionTime"`
|
||||||
Desc string `json:"descr"`
|
Desc string `json:"descr"`
|
||||||
DestructionTime uint64 `json:"destructionTime"`
|
DestructionTime uint64 `json:"destructionTime"`
|
||||||
DiskPath string `json:"diskPath"`
|
DiskPath string `json:"diskPath"`
|
||||||
GridID int `json:"gid"`
|
GridID int `json:"gid"`
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
ImageID int `json:"imageId"`
|
ImageID int `json:"imageId"`
|
||||||
Images []int `json:"images"`
|
Images []int `json:"images"`
|
||||||
// IOTune 'json:"iotune" - it is a dictionary
|
// IOTune 'json:"iotune" - it is a dictionary
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
// Order `json:"order"`
|
// Order `json:"order"`
|
||||||
ParentId int `json:"parentId"`
|
ParentId int `json:"parentId"`
|
||||||
PciSlot int `json:"pciSlot"`
|
PciSlot int `json:"pciSlot"`
|
||||||
// ResID string `json:"resId"`
|
// ResID string `json:"resId"`
|
||||||
// ResName string `json:"resName"`
|
// ResName string `json:"resName"`
|
||||||
// Params string `json:"params"`
|
// Params string `json:"params"`
|
||||||
Pool string `json:"pool"`
|
Pool string `json:"pool"`
|
||||||
PurgeTime uint64 `json:"purgeTime"`
|
PurgeTime uint64 `json:"purgeTime"`
|
||||||
// Role string `json:"role"`
|
// Role string `json:"role"`
|
||||||
SepType string `json:"sepType"`
|
SepType string `json:"sepType"`
|
||||||
SepID int `json:"sepid"`
|
SepID int `json:"sepid"`
|
||||||
SizeMax int `json:"sizeMax"`
|
SizeMax int `json:"sizeMax"`
|
||||||
SizeUsed int `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space
|
SizeUsed int `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space
|
||||||
Snapshots []SnapshotRecord `json:"snapshots"`
|
Snapshots []SnapshotRecord `json:"snapshots"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
TechStatus string `json:"techStatus"`
|
TechStatus string `json:"techStatus"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
ComputeID int `json:"vmid"`
|
ComputeID int `json:"vmid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OsUserRecord struct {
|
type OsUserRecord struct {
|
||||||
Guid string `json:"guid"`
|
Guid string `json:"guid"`
|
||||||
Login string `json:"login"`
|
Login string `json:"login"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
PubKey string `json:"pubkey"`
|
PubKey string `json:"pubkey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComputeGetAPI = "/restmachine/cloudapi/compute/get"
|
const ComputeGetAPI = "/restmachine/cloudapi/compute/get"
|
||||||
|
|
||||||
type ComputeGetResp struct {
|
type ComputeGetResp struct {
|
||||||
// ACLs `json:"ACL"` - it is a dictionary, special parsing required
|
// ACLs `json:"ACL"` - it is a dictionary, special parsing required
|
||||||
AccountID int `json:"accountId"`
|
AccountID int `json:"accountId"`
|
||||||
AccountName string `json:"accountName"`
|
AccountName string `json:"accountName"`
|
||||||
Arch string `json:"arch"`
|
Arch string `json:"arch"`
|
||||||
BootDiskSize int `json:"bootdiskSize"`
|
BootDiskSize int `json:"bootdiskSize"`
|
||||||
CloneReference int `json:"cloneReference"`
|
CloneReference int `json:"cloneReference"`
|
||||||
Clones []int `json:"clones"`
|
Clones []int `json:"clones"`
|
||||||
Cpus int `json:"cpus"`
|
Cpus int `json:"cpus"`
|
||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
Disks []DiskRecord `json:"disks"`
|
Disks []DiskRecord `json:"disks"`
|
||||||
GridID int `json:"gid"`
|
GridID int `json:"gid"`
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
ImageID int `json:"imageId"`
|
ImageID int `json:"imageId"`
|
||||||
ImageName string `json:"imageName"`
|
ImageName string `json:"imageName"`
|
||||||
Interfaces []InterfaceRecord `json:"interfaces`
|
Interfaces []InterfaceRecord `json:"interfaces`
|
||||||
LockStatus string `json:"lockStatus"`
|
LockStatus string `json:"lockStatus"`
|
||||||
ManagerID int `json:"managerId"`
|
ManagerID int `json:"managerId"`
|
||||||
ManagerType string `json:"manageType"`
|
ManagerType string `json:"manageType"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
NatableVinsID int `json:"natableVinsId"`
|
NatableVinsID int `json:"natableVinsId"`
|
||||||
NatableVinsIP string `json:"natableVinsIp"`
|
NatableVinsIP string `json:"natableVinsIp"`
|
||||||
NatableVinsName string `json:"natableVinsName"`
|
NatableVinsName string `json:"natableVinsName"`
|
||||||
NatableVinsNet string `json:"natableVinsNetwork"`
|
NatableVinsNet string `json:"natableVinsNetwork"`
|
||||||
NatableVinsNetName string `json:"natableVinsNetworkName"`
|
NatableVinsNetName string `json:"natableVinsNetworkName"`
|
||||||
OsUsers []OsUserRecord `json:"osUsers"`
|
OsUsers []OsUserRecord `json:"osUsers"`
|
||||||
Ram int `json:"ram"`
|
Ram int `json:"ram"`
|
||||||
RgID int `json:"rgId"`
|
RgID int `json:"rgId"`
|
||||||
RgName string `json:"rgName"`
|
RgName string `json:"rgName"`
|
||||||
SnapSets []SnapSetRecord `json:"snapSets"`
|
SnapSets []SnapSetRecord `json:"snapSets"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Tags []string `json:"tags"`
|
Tags []string `json:"tags"`
|
||||||
TechStatus string `json:"techStatus"`
|
TechStatus string `json:"techStatus"`
|
||||||
TotalDiskSize int `json:"totalDiskSize"`
|
TotalDiskSize int `json:"totalDiskSize"`
|
||||||
UpdatedBy string `json:"updatedBy"`
|
UpdatedBy string `json:"updatedBy"`
|
||||||
UpdateTime uint64 `json:"updateTime"`
|
UpdateTime uint64 `json:"updateTime"`
|
||||||
UserManaged bool `json:"userManaged"`
|
UserManaged bool `json:"userManaged"`
|
||||||
Vgpus []int `json:"vgpus"`
|
Vgpus []int `json:"vgpus"`
|
||||||
VinsConnected int `json:"vinsConnected"`
|
VinsConnected int `json:"vinsConnected"`
|
||||||
VirtualImageID int `json:"virtualImageId"`
|
VirtualImageID int `json:"virtualImageId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /restmachine/cloudapi/images/list API
|
// structures related to /restmachine/cloudapi/images/list API
|
||||||
//
|
//
|
||||||
type ImageRecord struct {
|
type ImageRecord struct {
|
||||||
AccountID uint `json:"accountId"`
|
AccountID uint `json:"accountId"`
|
||||||
Arch string `json:"architecture`
|
Arch string `json:"architecture`
|
||||||
BootType string `json:"bootType"`
|
BootType string `json:"bootType"`
|
||||||
IsBootable boo `json:"bootable"`
|
IsBootable bool `json:"bootable"`
|
||||||
IsCdrom bool `json:"cdrom"`
|
IsCdrom bool `json:"cdrom"`
|
||||||
Desc string `json:"description"`
|
Desc string `json:"description"`
|
||||||
IsHotResize bool `json:"hotResize"`
|
IsHotResize bool `json:"hotResize"`
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Pool string `json:"pool"`
|
Pool string `json:"pool"`
|
||||||
SepID int `json:"sepid"`
|
SepID int `json:"sepid"`
|
||||||
Size int `json:"size"`
|
Size int `json:"size"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
IsVirtual bool `json:"virtual"`
|
IsVirtual bool `json:"virtual"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImagesListAPI = "/restmachine/cloudapi/images/list"
|
const ImagesListAPI = "/restmachine/cloudapi/images/list"
|
||||||
type ImagesListParam struct {
|
|
||||||
AccountID int `json:"accountId"`
|
|
||||||
}
|
|
||||||
type ImagesListResp []ImageRecord
|
type ImagesListResp []ImageRecord
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/extnet/list API
|
// structures related to /cloudapi/extnet/list API
|
||||||
//
|
//
|
||||||
type ExtNetRecord struct {
|
type ExtNetRecord struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
IPCIDR string `json:"ipcidr"`
|
IPCIDR string `json:"ipcidr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExtNetListAPI = "/restmachine/cloudapi/extnet/list"
|
const ExtNetListAPI = "/restmachine/cloudapi/extnet/list"
|
||||||
type ExtNetListParam struct {
|
|
||||||
AccountID int `json:"accountId"`
|
|
||||||
}
|
|
||||||
type ExtNetListResp []ExtNetRecord
|
|
||||||
|
|
||||||
|
type ExtNetListResp []ExtNetRecord
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/accounts/list API
|
// structures related to /cloudapi/accounts/list API
|
||||||
//
|
//
|
||||||
type AccountRecord struct {
|
type AccountRecord struct {
|
||||||
ACLs []UserAclRecord `json:"acl"`
|
// ACLs []UserAclRecord `json:"acl"`
|
||||||
CreatedTime uint64 `json:"creationTime"`
|
// CreatedTime uint64 `json:"creationTime"`
|
||||||
DeletedTime uint64 `json:"deletionTime"`
|
// DeletedTime uint64 `json:"deletionTime"`
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
UpdatedTime uint64 `json:"updateTime"`
|
// UpdatedTime uint64 `json:"updateTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccountsListAPI = "/restmachine/cloudapi/accounts/list"
|
const AccountsGetAPI = "/restmachine/cloudapi/accounts/get" // returns AccountRecord superset
|
||||||
|
|
||||||
|
const AccountsListAPI = "/restmachine/cloudapi/accounts/list" // returns list of abdridged info about accounts
|
||||||
type AccountsListResp []AccountRecord
|
type AccountsListResp []AccountRecord
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/portforwarding/list API
|
// structures related to /cloudapi/portforwarding/list API
|
||||||
//
|
//
|
||||||
type PfwRecord struct {
|
type PfwRecord struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
LocalIP string `json:"localIp`
|
LocalIP string `json:"localIp`
|
||||||
LocalPort int `json:"localPort"`
|
LocalPort int `json:"localPort"`
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
PublicPortEnd int `json:"publicPortEnd"`
|
PublicPortEnd int `json:"publicPortEnd"`
|
||||||
PublicPortStart int `json:"publicPortStart"`
|
PublicPortStart int `json:"publicPortStart"`
|
||||||
ComputeID int `json:"vmId"`
|
ComputeID int `json:"vmId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComputePfwListAPI = "/restmachine/cloudapi/compute/pfwList"
|
const ComputePfwListAPI = "/restmachine/cloudapi/compute/pfwList"
|
||||||
|
|
||||||
type ComputePfwListResp []PfwRecord
|
type ComputePfwListResp []PfwRecord
|
||||||
|
|
||||||
type ComputePfwAddParam struct {
|
|
||||||
ComputeID int `json:"computeId"`
|
|
||||||
PublicPortStart int `json:"publicPortStart"`
|
|
||||||
PublicPortEnd int `json:"publicPortEnd"`
|
|
||||||
LocalBasePort int `json:"localBasePort"`
|
|
||||||
Protocol string `json:"proto"`
|
|
||||||
}
|
|
||||||
const ComputePfwAddAPI = "/restmachine/cloudapi/compute/pfwAdd"
|
const ComputePfwAddAPI = "/restmachine/cloudapi/compute/pfwAdd"
|
||||||
|
|
||||||
type ComputePfwDelParam struct {
|
|
||||||
ComputeID int `json:"computeId"`
|
|
||||||
RuleID int `json:"ruleId"`
|
|
||||||
PublicPortStart int `json:"publicPortStart"`
|
|
||||||
PublicPortEnd int `json:"publicPortEnd"`
|
|
||||||
LocalBasePort int `json:"localBasePort"`
|
|
||||||
Protocol string `json:"proto"`
|
|
||||||
}
|
|
||||||
const ComputePfwDelAPI = "/restmachine/cloudapi/compute/pfwDel"
|
const ComputePfwDelAPI = "/restmachine/cloudapi/compute/pfwDel"
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/compute/net Attach/Detach API
|
// structures related to /cloudapi/compute/net Attach/Detach API
|
||||||
//
|
//
|
||||||
type ComputeNetAttachParam struct {
|
|
||||||
ComputeID int `json:"computeId"`
|
|
||||||
NetType string `json:"netType"`
|
|
||||||
NetID int `json:"netId"`
|
|
||||||
IPAddr string `json:"apAddr"`
|
|
||||||
}
|
|
||||||
const ComputeNetAttachAPI = "/restmachine/cloudapi/compute/netAttach"
|
const ComputeNetAttachAPI = "/restmachine/cloudapi/compute/netAttach"
|
||||||
|
|
||||||
type ComputeNetDetachParam struct {
|
|
||||||
ComputeID int `json:"computeId"`
|
|
||||||
IPAddr string `json:"apAddr"`
|
|
||||||
MAC string `json:"mac"`
|
|
||||||
}
|
|
||||||
const ComputeNetDetachAPI = "/restmachine/cloudapi/compute/netDetach"
|
const ComputeNetDetachAPI = "/restmachine/cloudapi/compute/netDetach"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/compute/disk Attach/Detach API
|
// structures related to /cloudapi/compute/disk Attach/Detach API
|
||||||
//
|
//
|
||||||
type ComputeDiskManipulationParam struct {
|
|
||||||
ComputeID int `json:"computeId"`
|
|
||||||
DiskID int `json:"diskId"`
|
|
||||||
}
|
|
||||||
const ComputeDiskAttachAPI = "/restmachine/cloudapi/compute/diskAttach"
|
const ComputeDiskAttachAPI = "/restmachine/cloudapi/compute/diskAttach"
|
||||||
|
|
||||||
const ComputeDiskDetachAPI = "/restmachine/cloudapi/compute/diskDetach"
|
const ComputeDiskDetachAPI = "/restmachine/cloudapi/compute/diskDetach"
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/disks/create
|
// structures related to /cloudapi/disks/create
|
||||||
//
|
//
|
||||||
type DiskCreateParam struct {
|
type DiskCreateParam struct {
|
||||||
AccountID int `json:"accountId`
|
AccountID int `json:"accountId`
|
||||||
GridID int `json:"gid"`
|
GridID int `json:"gid"`
|
||||||
Name string `json:"string"`
|
Name string `json:"string"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Size int `json:"size"`
|
Size int `json:"size"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
SepID int `json:"sep_id"`
|
SepID int `json:"sep_id"`
|
||||||
Pool string `json:"pool"`
|
Pool string `json:"pool"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const DiskCreateAPI = "/restmachine/cloudapi/disks/create"
|
const DiskCreateAPI = "/restmachine/cloudapi/disks/create"
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/disks/get
|
// structures related to /cloudapi/disks/get
|
||||||
//
|
//
|
||||||
type DisksGetParam struct {
|
|
||||||
DiskID int `json:"diskId`
|
|
||||||
}
|
|
||||||
const DisksCreateAPI = "/restmachine/cloudapi/disks/create"
|
const DisksCreateAPI = "/restmachine/cloudapi/disks/create"
|
||||||
|
|
||||||
const DisksGetAPI = "/restmachine/cloudapi/disks/get" // Returns single DiskRecord on success
|
const DisksGetAPI = "/restmachine/cloudapi/disks/get" // Returns single DiskRecord on success
|
||||||
|
|
||||||
const DisksListAPI = "/restmachine/cloudapi/disks/list" // Returns list of DiskRecord on success
|
const DisksListAPI = "/restmachine/cloudapi/disks/list" // Returns list of DiskRecord on success
|
||||||
|
|||||||
@@ -18,34 +18,32 @@ limitations under the License.
|
|||||||
package decort
|
package decort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
"github.com/hashicorp/terraform/helper/validation"
|
"github.com/hashicorp/terraform/helper/validation"
|
||||||
// "github.com/hashicorp/terraform/terraform"
|
// "github.com/hashicorp/terraform/terraform"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var decsController *ControllerCfg
|
var decsController *ControllerCfg
|
||||||
|
|
||||||
func Provider() *schema.Provider {
|
func Provider() *schema.Provider {
|
||||||
return &schema.Provider {
|
return &schema.Provider{
|
||||||
Schema: map[string]*schema.Schema {
|
Schema: map[string]*schema.Schema{
|
||||||
"authenticator": {
|
"authenticator": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
StateFunc: stateFuncToLower,
|
StateFunc: stateFuncToLower,
|
||||||
ValidateFunc: validation.StringInSlice([]string{"oauth2", "legacy", "jwt"}, true), // ignore case while validating
|
ValidateFunc: validation.StringInSlice([]string{"oauth2", "legacy", "jwt"}, true), // ignore case while validating
|
||||||
Description: "Authentication mode to use when connecting to DECS cloud API. Should be one of 'oauth2', 'legacy' or 'jwt'.",
|
Description: "Authentication mode to use when connecting to DECORT cloud API. Should be one of 'oauth2', 'legacy' or 'jwt'.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"oauth2_url": {
|
"oauth2_url": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
StateFunc: stateFuncToLower,
|
StateFunc: stateFuncToLower,
|
||||||
DefaultFunc: schema.EnvDefaultFunc("DECS_OAUTH2_URL", nil),
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_OAUTH2_URL", nil),
|
||||||
Description: "The Oauth2 application URL in 'oauth2' authentication mode.",
|
Description: "OAuth2 application URL in 'oauth2' authentication mode.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"controller_url": {
|
"controller_url": {
|
||||||
@@ -53,67 +51,70 @@ func Provider() *schema.Provider {
|
|||||||
Required: true,
|
Required: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
StateFunc: stateFuncToLower,
|
StateFunc: stateFuncToLower,
|
||||||
Description: "The URL of DECS Cloud controller to use. API calls will be directed to this URL.",
|
Description: "URL of DECORT Cloud controller to use. API calls will be directed to this URL.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"user": {
|
"user": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
DefaultFunc: schema.EnvDefaultFunc("DECS_USER", nil),
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_USER", nil),
|
||||||
Description: "The user name for DECS cloud API operations in 'legacy' authentication mode.",
|
Description: "User name for DECORT cloud API operations in 'legacy' authentication mode.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"password": {
|
"password": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
DefaultFunc: schema.EnvDefaultFunc("DECS_PASSWORD", nil),
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_PASSWORD", nil),
|
||||||
Description: "The user password for DECS cloud API operations in 'legacy' authentication mode.",
|
Description: "User password for DECORT cloud API operations in 'legacy' authentication mode.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"app_id": {
|
"app_id": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
DefaultFunc: schema.EnvDefaultFunc("DECS_APP_ID", nil),
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_APP_ID", nil),
|
||||||
Description: "Application ID to access DECS cloud API in 'oauth2' authentication mode.",
|
Description: "Application ID to access DECORT cloud API in 'oauth2' authentication mode.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"app_secret": {
|
"app_secret": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
DefaultFunc: schema.EnvDefaultFunc("DECS_APP_SECRET", nil),
|
DefaultFunc: schema.EnvDefaultFunc("DECSORTAPP_SECRET", nil),
|
||||||
Description: "Application secret to access DECS cloud API in 'oauth2' authentication mode.",
|
Description: "Application secret to access DECORT cloud API in 'oauth2' authentication mode.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"jwt": {
|
"jwt": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
DefaultFunc: schema.EnvDefaultFunc("DECS_JWT", nil),
|
DefaultFunc: schema.EnvDefaultFunc("DECS_JWT", nil),
|
||||||
Description: "JWT to access DECS cloud API in 'jwt' authentication mode.",
|
Description: "JWT to access DECORT cloud API in 'jwt' authentication mode.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"allow_unverified_ssl": {
|
"allow_unverified_ssl": {
|
||||||
Type: schema.TypeBool,
|
Type: schema.TypeBool,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Default: false,
|
Default: false,
|
||||||
Description: "If set, DECS API will allow unverifiable SSL certificates.",
|
Description: "If true, DECORT API will not verify SSL certificates. Use this with caution and in trusted environments only!",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
ResourcesMap: map[string]*schema.Resource {
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"decort_resgroup": resourceResgroup(),
|
"decort_resgroup": resourceResgroup(),
|
||||||
"decort_kvmx86": resourceKvmX86(),
|
"decort_kvmvm": resourceCompute(),
|
||||||
"decort_disk": resourceDisk(),
|
"decort_disk": resourceDisk(),
|
||||||
"decort_vins": resourceVins(),
|
"decort_vins": resourceVins(),
|
||||||
|
// "decort_pfw": resourcePfw(),
|
||||||
},
|
},
|
||||||
|
|
||||||
DataSourcesMap: map[string]*schema.Resource {
|
DataSourcesMap: map[string]*schema.Resource{
|
||||||
|
// "decort_account": dataSourceAccount(),
|
||||||
"decort_resgroup": dataSourceResgroup(),
|
"decort_resgroup": dataSourceResgroup(),
|
||||||
"decs_kvmx86": dataSourceCompute(),
|
"decort_kvmvm": dataSourceCompute(),
|
||||||
"decort_image": dataSourceImage(),
|
"decort_image": dataSourceImage(),
|
||||||
"decort_disk": dataSourceDisk(),
|
"decort_disk": dataSourceDisk(),
|
||||||
"decort_vins": dataSourceVins(),
|
"decort_vins": dataSourceVins(),
|
||||||
|
// "decort_pfw": dataSourcePfw(),
|
||||||
},
|
},
|
||||||
|
|
||||||
ConfigureFunc: providerConfigure,
|
ConfigureFunc: providerConfigure,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,4 +129,4 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return decsController, nil
|
return decsController, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,42 +16,43 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
Technology platfom.
|
Technology platfom.
|
||||||
|
|
||||||
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package decort
|
package decort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
// "net/url"
|
// "net/url"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
// "github.com/hashicorp/terraform/helper/validation"
|
// "github.com/hashicorp/terraform/helper/validation"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func flattenResgroup(d *schema.ResourceData, rg_facts string) error {
|
func flattenResgroup(d *schema.ResourceData, rg_facts string) error {
|
||||||
// NOTE: this function modifies ResourceData argument - as such it should never be called
|
// NOTE: this function modifies ResourceData argument - as such it should never be called
|
||||||
// from resourceRsgroupExists(...) method
|
// from resourceRsgroupExists(...) method
|
||||||
log.Debugf("%s", rg_facts)
|
// log.Debugf("%s", rg_facts)
|
||||||
log.Debugf("flattenResgroup: ready to decode response body from %q", CloudspacesGetAPI)
|
log.Debugf("flattenResgroup: ready to decode response body from API")
|
||||||
details := ResgroupGetResp{}
|
details := ResgroupGetResp{}
|
||||||
err := json.Unmarshal([]byte(rg_facts), &details)
|
err := json.Unmarshal([]byte(rg_facts), &details)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("flattenResgroup: decoded ResGroup name %q / ID %d, account ID %d, public IP %q",
|
log.Debugf("flattenResgroup: decoded RG name %q / ID %d, account ID %d",
|
||||||
details.Name, details.ID, details.AccountID, details.PublicIP)
|
details.Name, details.ID, details.AccountID)
|
||||||
|
|
||||||
d.SetId(fmt.Sprintf("%d", details.ID))
|
d.SetId(fmt.Sprintf("%d", details.ID))
|
||||||
|
d.Set("rg_id", details.ID)
|
||||||
d.Set("name", details.Name)
|
d.Set("name", details.Name)
|
||||||
|
d.Set("account_name", details.AccountName)
|
||||||
d.Set("account_id", details.AccountID)
|
d.Set("account_id", details.AccountID)
|
||||||
d.Set("grid_id", details.GridID)
|
d.Set("grid_id", details.GridID)
|
||||||
d.Set("desc", details.Description)
|
d.Set("desc", details.Description)
|
||||||
@@ -73,7 +74,7 @@ func dataSourceResgroupRead(d *schema.ResourceData, m interface{}) error {
|
|||||||
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||||
if rg_facts == "" {
|
if rg_facts == "" {
|
||||||
// if empty string is returned from utilityResgroupCheckPresence then there is no
|
// if empty string is returned from utilityResgroupCheckPresence then there is no
|
||||||
// such resource group and err tells so - just return it to the calling party
|
// such resource group and err tells so - just return it to the calling party
|
||||||
d.SetId("") // ensure ID is empty in this case
|
d.SetId("") // ensure ID is empty in this case
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -81,92 +82,97 @@ func dataSourceResgroupRead(d *schema.ResourceData, m interface{}) error {
|
|||||||
return flattenResgroup(d, rg_facts)
|
return flattenResgroup(d, rg_facts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func dataSourceResgroup() *schema.Resource {
|
func dataSourceResgroup() *schema.Resource {
|
||||||
return &schema.Resource {
|
return &schema.Resource{
|
||||||
SchemaVersion: 1,
|
SchemaVersion: 1,
|
||||||
|
|
||||||
Read: dataSourceResgroupRead,
|
Read: dataSourceResgroupRead,
|
||||||
|
|
||||||
Timeouts: &schema.ResourceTimeout {
|
Timeouts: &schema.ResourceTimeout{
|
||||||
Read: &Timeout30s,
|
Read: &Timeout30s,
|
||||||
Default: &Timeout60s,
|
Default: &Timeout60s,
|
||||||
},
|
},
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema {
|
Schema: map[string]*schema.Schema{
|
||||||
"name": {
|
"name": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Optional: true,
|
||||||
Description: "Name of this resource group. Names are case sensitive and unique within the context of an account.",
|
Description: "Name of the resource group. Names are case sensitive and unique within the context of an account.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"account": &schema.Schema {
|
"rg_id": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the resource group. If this ID is specified, then resource group name is ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_name": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: Optional,
|
||||||
Description: "Name of the account, which this resource group belongs to.",
|
Description: "Name of the account, which this resource group belongs to.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"account_id": &schema.Schema {
|
"account_id": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Computed: true,
|
Optional: Optional,
|
||||||
Description: "Unique ID of the account, which this resource group belongs to.",
|
Description: "Unique ID of the account, which this resource group belongs to. If account ID is specified, then account name is ignored.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"desc": &schema.Schema {
|
"desc": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "User-defined text description of this resource group.",
|
Description: "User-defined text description of this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"grid_id": &schema.Schema {
|
"grid_id": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "Unique ID of the grid, where this resource group is deployed.",
|
Description: "Unique ID of the grid, where this resource group is deployed.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"quotas": {
|
"quotas": {
|
||||||
Type: schema.TypeList,
|
Type: schema.TypeList,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
MaxItems: 1,
|
MaxItems: 1,
|
||||||
Elem: &schema.Resource {
|
Elem: &schema.Resource{
|
||||||
Schema: quotaRgSubresourceSchema(), // this is a dictionary
|
Schema: quotaRgSubresourceSchema(), // this is a dictionary
|
||||||
},
|
},
|
||||||
Description: "Quotas on the resources for this resource group.",
|
Description: "Quotas on the resources for this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"status": {
|
"status": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "Current status of this resource group.",
|
Description: "Current status of this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"def_net": &schema.Schema {
|
"def_net": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "Type of the default network for this resource group.",
|
Description: "Type of the default network for this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"def_net_id": &schema.Schema {
|
"def_net_id": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "ID of the default network for this resource group (if any).",
|
Description: "ID of the default network for this resource group (if any).",
|
||||||
},
|
},
|
||||||
|
|
||||||
"vins": {
|
"vins": {
|
||||||
Type: schema.TypeList, // this is a list of ints
|
Type: schema.TypeList, // this is a list of ints
|
||||||
Computed: true,
|
Computed: true,
|
||||||
MaxItems: LimitMaxVinsPerResgroup,
|
MaxItems: LimitMaxVinsPerResgroup,
|
||||||
Elem: &schema.Schema {
|
Elem: &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
},
|
},
|
||||||
Description: "List of VINs deployed in this resource group.",
|
Description: "List of VINs deployed in this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"computes": {
|
"computes": {
|
||||||
Type: schema.TypeList, //t his is a list of ints
|
Type: schema.TypeList, //t his is a list of ints
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Elem: &schema.Schema {
|
Elem: &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
},
|
},
|
||||||
Description: "List of computes deployed in this resource group.",
|
Description: "List of computes deployed in this resource group.",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,57 +15,51 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
Technology platfom.
|
Technology platfom.
|
||||||
|
|
||||||
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package decort
|
package decort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
|
func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
// First validate that we have all parameters required to create the new Resource Group
|
// First validate that we have all parameters required to create the new Resource Group
|
||||||
arg_set := false
|
|
||||||
account_name, arg_set := d.GetOk("account")
|
|
||||||
if !arg_set {
|
|
||||||
return fmt.Errorf("Cannot create new RG: missing account.")
|
|
||||||
}
|
|
||||||
rg_name, arg_set := d.GetOk("name")
|
|
||||||
if !arg_set {
|
|
||||||
return fmt.Errorf("Cannot create new RG: missing name.")
|
|
||||||
}
|
|
||||||
grid_id, arg_set := d.GetOk("grid_id")
|
|
||||||
if !arg_set {
|
|
||||||
return fmt.Errorf("Cannot create new RG %q for account %q: missing Grid ID.",
|
|
||||||
rg_name.(string), account_name.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
// all required parameters are set in the schema - we can continue with RG creation
|
|
||||||
log.Debugf("resourceResgroupCreate: called for RG name %q, account name %q",
|
|
||||||
account_name.(string), rg_name.(string))
|
|
||||||
|
|
||||||
// Valid account ID is required to create new resource group
|
// Valid account ID is required to create new resource group
|
||||||
// obtain Account ID by account name - it should not be zero on success
|
// obtain Account ID by account name - it should not be zero on success
|
||||||
validated_account_id, err := utilityGetAccountIdByName(account_name.(string), m)
|
validated_account_id, err := utilityGetAccountIdBySchema(d, m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rg_name, arg_set := d.GetOk("name")
|
||||||
|
if !arg_set {
|
||||||
|
return fmt.Errorf("Cannot create new RG: missing name.")
|
||||||
|
}
|
||||||
|
|
||||||
|
grid_id, arg_set := d.GetOk("grid_id")
|
||||||
|
if !arg_set {
|
||||||
|
return fmt.Errorf("Cannot create new RG %q in account ID %d: missing Grid ID.",
|
||||||
|
rg_name.(string), validated_account_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// all required parameters are set in the schema - we can continue with RG creation
|
||||||
|
log.Debugf("resourceResgroupCreate: called for RG name %q, account ID %d",
|
||||||
|
rg_name.(string), validated_account_id)
|
||||||
|
|
||||||
// quota settings are optional
|
// quota settings are optional
|
||||||
set_quota := false
|
set_quota := false
|
||||||
var quota_record QuotaRecord
|
var quota_record QuotaRecord
|
||||||
arg_value, arg_set = d.GetOk("quota")
|
arg_value, arg_set = d.GetOk("quota")
|
||||||
if arg_set {
|
if arg_set {
|
||||||
log.Debugf("resourceResgroupCreate: setting Quota on RG requested")
|
log.Debugf("resourceResgroupCreate: setting Quota on RG requested")
|
||||||
@@ -75,34 +69,34 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
|
|||||||
|
|
||||||
controller := m.(*ControllerCfg)
|
controller := m.(*ControllerCfg)
|
||||||
log.Debugf("resourceResgroupCreate: called by user %q for RG name %q, account %q / ID %d, Grid ID %d",
|
log.Debugf("resourceResgroupCreate: called by user %q for RG name %q, account %q / ID %d, Grid ID %d",
|
||||||
controller.getdecortUsername(),
|
controller.getdecortUsername(),
|
||||||
rg_name.(string), account_name.(string), validated_account_id, gird_id.(int))
|
rg_name.(string), account_name.(string), validated_account_id, gird_id.(int))
|
||||||
/*
|
/*
|
||||||
type ResgroupCreateParam struct {
|
type ResgroupCreateParam struct {
|
||||||
AccountID int `json:"accountId"`
|
AccountID int `json:"accountId"`
|
||||||
GridId int `json:"gid"`
|
GridId int `json:"gid"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Ram int `json:"maxMemoryCapacity"`
|
Ram int `json:"maxMemoryCapacity"`
|
||||||
Disk int `json:"maxVDiskCapacity"`
|
Disk int `json:"maxVDiskCapacity"`
|
||||||
Cpu int `json:"maxCPUCapacity"`
|
Cpu int `json:"maxCPUCapacity"`
|
||||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||||
ExtIPs int `json:"maxNumPublicIP"`
|
ExtIPs int `json:"maxNumPublicIP"`
|
||||||
Owner string `json:"owner"`
|
Owner string `json:"owner"`
|
||||||
DefNet string `json:"def_net"`
|
DefNet string `json:"def_net"`
|
||||||
IPCidr string `json:"ipcidr"`
|
IPCidr string `json:"ipcidr"`
|
||||||
Desc string `json:"decs"`
|
Desc string `json:"decs"`
|
||||||
Reason string `json:"reason"`
|
Reason string `json:"reason"`
|
||||||
ExtNetID int `json:"extNetId"`
|
ExtNetID int `json:"extNetId"`
|
||||||
ExtIP string `json:"extIp"`
|
ExtIP string `json:"extIp"`
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
url_values := &url.Values{}
|
url_values := &url.Values{}
|
||||||
url_values.Add("accountId", fmt.Sprintf("%d", validated_account_id))
|
url_values.Add("accountId", fmt.Sprintf("%d", validated_account_id))
|
||||||
url_values.Add("name", rg_name.(string))
|
url_values.Add("name", rg_name.(string))
|
||||||
url_values.Add("gid", fmt.Sprintf("%d", grid_id.(int)))
|
url_values.Add("gid", fmt.Sprintf("%d", grid_id.(int)))
|
||||||
url_values.Add("owner", controller.getdecortUsername())
|
url_values.Add("owner", controller.getdecortUsername())
|
||||||
|
|
||||||
// pass quota values as set
|
// pass quota values as set
|
||||||
if set_quota {
|
if set_quota {
|
||||||
url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quota_record.Cpu))
|
url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quota_record.Cpu))
|
||||||
@@ -133,7 +127,7 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
|
|||||||
if arg_set {
|
if arg_set {
|
||||||
ulr_values.Add("extIp", ext_ip.(string))
|
ulr_values.Add("extIp", ext_ip.(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
api_resp, err := controller.decortAPICall("POST", ResgroupCreateAPI, url_values)
|
api_resp, err := controller.decortAPICall("POST", ResgroupCreateAPI, url_values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -147,12 +141,12 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func resourceResgroupRead(d *schema.ResourceData, m interface{}) error {
|
func resourceResgroupRead(d *schema.ResourceData, m interface{}) error {
|
||||||
log.Debugf("resourceResgroupRead: called for RG name %q, account name %q",
|
log.Debugf("resourceResgroupRead: called for RG name %q, account name %q",
|
||||||
d.Get("name").(string), d.Get("account").(string))
|
d.Get("name").(string), d.Get("account_name").(string))
|
||||||
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||||
if rg_facts == "" {
|
if rg_facts == "" {
|
||||||
// if empty string is returned from utilityResgroupCheckPresence then there is no
|
// if empty string is returned from utilityResgroupCheckPresence then there is no
|
||||||
// such resource group and err tells so - just return it to the calling party
|
// such resource group and err tells so - just return it to the calling party
|
||||||
d.SetId("") // ensure ID is empty
|
d.SetId("") // ensure ID is empty
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -161,8 +155,8 @@ func resourceResgroupRead(d *schema.ResourceData, m interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
|
func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
|
||||||
log.Debugf("resourceResgroupUpdate: called for RG name %q, account name %q",
|
log.Debugf("resourceResgroupUpdate: called for RG name %q, account name %q",
|
||||||
d.Get("name").(string), d.Get("account").(string))
|
d.Get("name").(string), d.Get("account").(string))
|
||||||
|
|
||||||
do_update := false
|
do_update := false
|
||||||
|
|
||||||
@@ -179,7 +173,7 @@ func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
|
|||||||
url_values.Add("name", name_new.(string))
|
url_values.Add("name", name_new.(string))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quota_value, quota_set := d.GetOk("quota")
|
quota_value, quota_set := d.GetOk("quota")
|
||||||
if quota_set {
|
if quota_set {
|
||||||
log.Debugf("resourceResgroupUpdate: quota specified - looking for deltas from the old quota.")
|
log.Debugf("resourceResgroupUpdate: quota specified - looking for deltas from the old quota.")
|
||||||
@@ -192,25 +186,25 @@ func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
|
|||||||
log.Debugf("resourceResgroupUpdate: Cpu diff %d <- %d", quotarecord_new.Cpu, quotarecord_old.Cpu)
|
log.Debugf("resourceResgroupUpdate: Cpu diff %d <- %d", quotarecord_new.Cpu, quotarecord_old.Cpu)
|
||||||
url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quotarecord_new.Cpu))
|
url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quotarecord_new.Cpu))
|
||||||
}
|
}
|
||||||
|
|
||||||
if quotarecord_new.Disk != quotarecord_old.Disk {
|
if quotarecord_new.Disk != quotarecord_old.Disk {
|
||||||
do_update = true
|
do_update = true
|
||||||
log.Debugf("resourceResgroupUpdate: Disk diff %d <- %d", quotarecord_new.Disk, quotarecord_old.Disk)
|
log.Debugf("resourceResgroupUpdate: Disk diff %d <- %d", quotarecord_new.Disk, quotarecord_old.Disk)
|
||||||
url_values.Add("maxVDiskCapacity", fmt.Sprintf("%d", quotarecord_new.Disk))
|
url_values.Add("maxVDiskCapacity", fmt.Sprintf("%d", quotarecord_new.Disk))
|
||||||
}
|
}
|
||||||
|
|
||||||
if quotarecord_new.Ram != quotarecord_old.Ram {
|
if quotarecord_new.Ram != quotarecord_old.Ram {
|
||||||
do_update = true
|
do_update = true
|
||||||
log.Debugf("resourceResgroupUpdate: Ram diff %f <- %f", quotarecord_new.Ram, quotarecord_old.Ram)
|
log.Debugf("resourceResgroupUpdate: Ram diff %f <- %f", quotarecord_new.Ram, quotarecord_old.Ram)
|
||||||
url_values.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotarecord_new.Ram))
|
url_values.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotarecord_new.Ram))
|
||||||
}
|
}
|
||||||
|
|
||||||
if quotarecord_new.ExtTraffic != quotarecord_old.ExtTraffic {
|
if quotarecord_new.ExtTraffic != quotarecord_old.ExtTraffic {
|
||||||
do_update = true
|
do_update = true
|
||||||
log.Debugf("resourceResgroupUpdate: NetTraffic diff %d <- %d", quotarecord_new.ExtTraffic, quotarecord_old.ExtTraffic)
|
log.Debugf("resourceResgroupUpdate: NetTraffic diff %d <- %d", quotarecord_new.ExtTraffic, quotarecord_old.ExtTraffic)
|
||||||
url_values.Add("maxNetworkPeerTransfer", fmt.Sprintf("%d", quotarecord_new.NetTraffic))
|
url_values.Add("maxNetworkPeerTransfer", fmt.Sprintf("%d", quotarecord_new.NetTraffic))
|
||||||
}
|
}
|
||||||
|
|
||||||
if quotarecord_new.ExtIPs != quotarecord_old.ExtIPs {
|
if quotarecord_new.ExtIPs != quotarecord_old.ExtIPs {
|
||||||
do_update = true
|
do_update = true
|
||||||
log.Debugf("resourceResgroupUpdate: ExtIPs diff %d <- %d", quotarecord_new.ExtIPs, quotarecord_old.ExtIPs)
|
log.Debugf("resourceResgroupUpdate: ExtIPs diff %d <- %d", quotarecord_new.ExtIPs, quotarecord_old.ExtIPs)
|
||||||
@@ -237,19 +231,19 @@ func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
|
|||||||
} else {
|
} else {
|
||||||
log.Debugf("resourceResgroupUpdate: no difference between old and new state - no update on the RG will be done")
|
log.Debugf("resourceResgroupUpdate: no difference between old and new state - no update on the RG will be done")
|
||||||
}
|
}
|
||||||
|
|
||||||
return resourceResgroupRead(d, m)
|
return resourceResgroupRead(d, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceResgroupDelete(d *schema.ResourceData, m interface{}) error {
|
func resourceResgroupDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
// NOTE: this method forcibly destroys target resource group with flag "permanently", so there is no way to
|
// NOTE: this method forcibly destroys target resource group with flag "permanently", so there is no way to
|
||||||
// restore the destroyed resource group as well all Computes & VINSes that existed in it
|
// restore the destroyed resource group as well all Computes & VINSes that existed in it
|
||||||
log.Debugf("resourceResgroupDelete: called for RG name %q, account name %q",
|
log.Debugf("resourceResgroupDelete: called for RG name %q, account name %q",
|
||||||
d.Get("name").(string), d.Get("account").(string))
|
d.Get("name").(string), d.Get("account_name").(string))
|
||||||
|
|
||||||
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||||
if rg_facts == "" {
|
if rg_facts == "" {
|
||||||
// the target RG does not exist - in this case according to Terraform best practice
|
// the target RG does not exist - in this case according to Terraform best practice
|
||||||
// we exit from Destroy method without error
|
// we exit from Destroy method without error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -282,7 +276,7 @@ func resourceResgroupExists(d *schema.ResourceData, m interface{}) (bool, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func resourceResgroup() *schema.Resource {
|
func resourceResgroup() *schema.Resource {
|
||||||
return &schema.Resource {
|
return &schema.Resource{
|
||||||
SchemaVersion: 1,
|
SchemaVersion: 1,
|
||||||
|
|
||||||
Create: resourceResgroupCreate,
|
Create: resourceResgroupCreate,
|
||||||
@@ -291,7 +285,7 @@ func resourceResgroup() *schema.Resource {
|
|||||||
Delete: resourceResgroupDelete,
|
Delete: resourceResgroupDelete,
|
||||||
Exists: resourceResgroupExists,
|
Exists: resourceResgroupExists,
|
||||||
|
|
||||||
Timeouts: &schema.ResourceTimeout {
|
Timeouts: &schema.ResourceTimeout{
|
||||||
Create: &Timeout180s,
|
Create: &Timeout180s,
|
||||||
Read: &Timeout30s,
|
Read: &Timeout30s,
|
||||||
Update: &Timeout180s,
|
Update: &Timeout180s,
|
||||||
@@ -299,103 +293,109 @@ func resourceResgroup() *schema.Resource {
|
|||||||
Default: &Timeout60s,
|
Default: &Timeout60s,
|
||||||
},
|
},
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema {
|
Schema: map[string]*schema.Schema{
|
||||||
"name": &schema.Schema {
|
"name": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
Description: "Name of this resource group. Names are case sensitive and unique within the context of a account.",
|
Description: "Name of this resource group. Names are case sensitive and unique within the context of a account.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"account": &schema.Schema {
|
"account_id": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the account, which this resource group belongs to. If account ID is specified, then account name is ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_name": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Optional: true,
|
||||||
Description: "Name of the account, which this resource group belongs to.",
|
Description: "Name of the account, which this resource group belongs to.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"def_net": &schema.Schema {
|
"def_net": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Default: "PRIVATE"
|
Default: "PRIVATE",
|
||||||
Description: "Type of the network, which this resource group will use as default for its computes - PRIVATE or PUBLIC or NONE.",
|
Description: "Type of the network, which this resource group will use as default for its computes - PRIVATE or PUBLIC or NONE.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"ipcidr": &schema.Schema {
|
"ipcidr": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Description: "Address of the netowrk inside the private network segment (aka ViNS) if def_net=PRIVATE",
|
Description: "Address of the netowrk inside the private network segment (aka ViNS) if def_net=PRIVATE",
|
||||||
},
|
},
|
||||||
|
|
||||||
"ext_net_id": &schema.Schema {
|
"ext_net_id": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Default: 0,
|
Default: 0,
|
||||||
Description: "ID of the external network, which this resource group will use as default for its computes if def_net=PUBLIC",
|
Description: "ID of the external network, which this resource group will use as default for its computes if def_net=PUBLIC",
|
||||||
},
|
},
|
||||||
|
|
||||||
"ext_ip": &schema.Schema {
|
"ext_ip": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Description: "IP address on the external netowrk to request, if def_net=PUBLIC",
|
Description: "IP address on the external netowrk to request, if def_net=PUBLIC",
|
||||||
},
|
},
|
||||||
|
|
||||||
"account_id": &schema.Schema {
|
"account_id": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "Unique ID of the account, which this resource group belongs to.",
|
Description: "Unique ID of the account, which this resource group belongs to.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"grid_id": &schema.Schema {
|
"grid_id": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Required: true,
|
Required: true,
|
||||||
Description: "Unique ID of the grid, where this resource group is deployed.",
|
Description: "Unique ID of the grid, where this resource group is deployed.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"quota": {
|
"quota": {
|
||||||
Type: schema.TypeList,
|
Type: schema.TypeList,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
MaxItems: 1,
|
MaxItems: 1,
|
||||||
Elem: &schema.Resource {
|
Elem: &schema.Resource{
|
||||||
Schema: quotasSubresourceSchema(),
|
Schema: quotasSubresourceSchema(),
|
||||||
},
|
},
|
||||||
Description: "Quota settings for this resource group.",
|
Description: "Quota settings for this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"desc": {
|
"desc": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Description: "User-defined text description of this resource group.",
|
Description: "User-defined text description of this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"status": {
|
"status": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "Current status of this resource group.",
|
Description: "Current status of this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"def_net_id": &schema.Schema {
|
"def_net_id": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "ID of the default network for this resource group (if any).",
|
Description: "ID of the default network for this resource group (if any).",
|
||||||
},
|
},
|
||||||
|
|
||||||
"vins": {
|
"vins": {
|
||||||
Type: schema.TypeList, // this is a list of ints
|
Type: schema.TypeList, // this is a list of ints
|
||||||
Computed: true,
|
Computed: true,
|
||||||
MaxItems: LimitMaxVinsPerResgroup,
|
MaxItems: LimitMaxVinsPerResgroup,
|
||||||
Elem: &schema.Schema {
|
Elem: &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
},
|
},
|
||||||
Description: "List of VINs deployed in this resource group.",
|
Description: "List of VINs deployed in this resource group.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"computes": {
|
"computes": {
|
||||||
Type: schema.TypeList, // this is a list of ints
|
Type: schema.TypeList, // this is a list of ints
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Elem: &schema.Schema {
|
Elem: &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
},
|
},
|
||||||
Description: "List of computes deployed in this resource group.",
|
Description: "List of computes deployed in this resource group.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,20 +16,20 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
Technology platfom.
|
Technology platfom.
|
||||||
|
|
||||||
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package decort
|
package decort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
// "strconv"
|
// "strconv"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
@@ -52,18 +52,18 @@ func (ctrl *ControllerCfg) utilityResgroupConfigGet(rgid int) (*ResgroupGetResp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ret := &ResgroupConfig{}
|
ret := &ResgroupConfig{}
|
||||||
ret.AccountID = model.AccountID
|
ret.AccountID = model.AccountID
|
||||||
ret.Location = model.Location
|
ret.Location = model.Location
|
||||||
ret.Name = model.Name
|
ret.Name = model.Name
|
||||||
ret.ID = rgid
|
ret.ID = rgid
|
||||||
ret.GridID = model.GridID
|
ret.GridID = model.GridID
|
||||||
ret.ExtIP = model.ExtIP // legacy field for VDC - this will eventually become obsoleted by true Resource Groups
|
ret.ExtIP = model.ExtIP // legacy field for VDC - this will eventually become obsoleted by true Resource Groups
|
||||||
// Quota ResgroupQuotaConfig
|
// Quota ResgroupQuotaConfig
|
||||||
// Network NetworkConfig
|
// Network NetworkConfig
|
||||||
*/
|
*/
|
||||||
log.Debugf("utilityResgroupConfigGet: account ID %d, GridID %d, Name %s",
|
log.Debugf("utilityResgroupConfigGet: account ID %d, GridID %d, Name %s",
|
||||||
model.AccountID, model.GridID, model.Name)
|
model.AccountID, model.GridID, model.Name)
|
||||||
|
|
||||||
return model, nil
|
return model, nil
|
||||||
}
|
}
|
||||||
@@ -71,31 +71,58 @@ func (ctrl *ControllerCfg) utilityResgroupConfigGet(rgid int) (*ResgroupGetResp,
|
|||||||
// On success this function returns a string, as returned by API rg/get, which could be unmarshalled
|
// On success this function returns a string, as returned by API rg/get, which could be unmarshalled
|
||||||
// into ResgroupGetResp structure
|
// into ResgroupGetResp structure
|
||||||
func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string, error) {
|
func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string, error) {
|
||||||
// This function tries to locate resource group by its name and account name.
|
// This function tries to locate resource group by one of the following algorithms depending
|
||||||
// If succeeded, it returns non empty string that contains JSON formatted facts about the
|
// on the parameters passed:
|
||||||
|
// - if resource group ID is specified -> by RG ID
|
||||||
|
// - if resource group name is specifeid -> by RG name and either account ID or account name
|
||||||
|
//
|
||||||
|
// If succeeded, it returns non empty string that contains JSON formatted facts about the
|
||||||
// resource group as returned by cloudspaces/get API call.
|
// resource group as returned by cloudspaces/get API call.
|
||||||
// Otherwise it returns empty string and meaningful error.
|
// Otherwise it returns empty string and meaningful error.
|
||||||
//
|
//
|
||||||
// NOTE: As our provider always deletes RGs permanently, there is no "restore" method and
|
// NOTE: As our provider always deletes RGs permanently, there is no "restore" method and
|
||||||
// consequently we are not interested in matching RGs in DELETED state. Hence, we call
|
// consequently we are not interested in matching RGs in DELETED state. Hence, we call
|
||||||
// .../rg/list API with includedeleted=false
|
// .../rg/list API with includedeleted=false
|
||||||
//
|
//
|
||||||
// This function does not modify its ResourceData argument, so it is safe to use it as core
|
// This function does not modify its ResourceData argument, so it is safe to use it as core
|
||||||
// method for the Terraform resource Exists method.
|
// method for the Terraform resource Exists method.
|
||||||
//
|
//
|
||||||
name := d.Get("name").(string)
|
|
||||||
account_name := d.Get("account").(string)
|
|
||||||
|
|
||||||
controller := m.(*ControllerCfg)
|
controller := m.(*ControllerCfg)
|
||||||
url_values := &url.Values{}
|
url_values := &url.Values{}
|
||||||
|
|
||||||
|
rg_id, arg_set := d.GetOk("rg_id")
|
||||||
|
if arg_set {
|
||||||
|
// go straight for the RG by its ID
|
||||||
|
log.Debugf("utilityResgroupCheckPresence: locating RG by its ID %d", rg_id.(int))
|
||||||
|
url_values.Add("rgId", fmt.Sprintf("%d", rg_id.(int)))
|
||||||
|
rg_facts, err := controller.decortAPICall("POST", ResgroupGetAPI, url_values)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return rg_facts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rg_name, arg_set := d.GetOk("name")
|
||||||
|
if !arg_set {
|
||||||
|
// no RG ID and no RG name - we cannot locate resource group in this case
|
||||||
|
return "", fmt.Error("Cannot check resource group presence if name is empty and no resource group ID specified.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid account ID is required to locate a resource group
|
||||||
|
// obtain Account ID by account name - it should not be zero on success
|
||||||
|
validated_account_id, err := utilityGetAccountIdBySchema(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
url_values.Add("includedeleted", "false")
|
url_values.Add("includedeleted", "false")
|
||||||
body_string, err := controller.decortAPICall("POST", ResgroupListAPI, url_values)
|
body_string, err := controller.decortAPICall("POST", ResgroupListAPI, url_values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
// log.Debugf("%s", body_string)
|
||||||
log.Debugf("%s", body_string)
|
// log.Debugf("utilityResgroupCheckPresence: ready to decode response body from %q", ResgroupListAPI)
|
||||||
log.Debugf("utilityResgroupCheckPresence: ready to decode response body from %q", ResgroupListAPI)
|
|
||||||
model := ResgroupListResp{}
|
model := ResgroupListResp{}
|
||||||
err = json.Unmarshal([]byte(body_string), &model)
|
err = json.Unmarshal([]byte(body_string), &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,15 +131,15 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string
|
|||||||
|
|
||||||
log.Debugf("utilityResgroupCheckPresence: traversing decoded Json of length %d", len(model))
|
log.Debugf("utilityResgroupCheckPresence: traversing decoded Json of length %d", len(model))
|
||||||
for index, item := range model {
|
for index, item := range model {
|
||||||
// need to match RG by name & account name
|
// match by RG name & account ID
|
||||||
if item.Name == name && item.AccountName == account_name {
|
if item.Name == rg_name.(string) && item.AccountID == validated_account_id {
|
||||||
log.Debugf("utilityResgroupCheckPresence: match RG name %q / ID %d, account %q at index %d",
|
log.Debugf("utilityResgroupCheckPresence: match RG name %q / ID %d, account ID %d at index %d",
|
||||||
item.Name, item.ID, item.AccountName, index)
|
item.Name, item.ID, item.AccountID, index)
|
||||||
|
|
||||||
// not all required information is returned by rg/list API, so we need to initiate one more
|
// not all required information is returned by rg/list API, so we need to initiate one more
|
||||||
// call to rg/get to obtain extra data to complete Resource population.
|
// call to rg/get to obtain extra data to complete Resource population.
|
||||||
// Namely, we need to extract resource quota settings
|
// Namely, we need resource quota settings
|
||||||
req_values := &url.Values{}
|
req_values := &url.Values{}
|
||||||
req_values.Add("rgId", fmt.Sprintf("%d", item.ID))
|
req_values.Add("rgId", fmt.Sprintf("%d", item.ID))
|
||||||
body_string, err := controller.decortAPICall("POST", ResgroupGetAPI, req_values)
|
body_string, err := controller.decortAPICall("POST", ResgroupGetAPI, req_values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -123,32 +150,5 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("Cannot find RG name %q owned by account %q", name, account_name)
|
return "", fmt.Errorf("Cannot find RG name %q owned by account ID %d", name, validated_account_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func utilityGetAccountIdByName(account_name string, m interface{}) (int, error) {
|
|
||||||
controller := m.(*ControllerCfg)
|
|
||||||
url_values := &url.Values{}
|
|
||||||
body_string, err := controller.decortAPICall("POST", AccountsListAPI, url_values)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
model := AccountsListResp{}
|
|
||||||
err = json.Unmarshal([]byte(body_string), &model)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("utilityGetAccountIdByName: traversing decoded Json of length %d", len(model))
|
|
||||||
for index, item := range model {
|
|
||||||
// need to match Account by name
|
|
||||||
if item.Name == account_name {
|
|
||||||
log.Debugf("utilityGetAccountIdByName: match Account name %q / ID %d at index %d",
|
|
||||||
item.Name, item.ID, index)
|
|
||||||
return item.ID, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, fmt.Errorf("Cannot find account %q for the current user. Check account name and your access rights", account_name)
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2019 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -15,10 +15,9 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package decs
|
package decort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
@@ -26,7 +25,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func makeSshKeysConfig(arg_list []interface{}) (sshkeys []SshKeyConfig, count int) {
|
func makeSshKeysConfig(arg_list []interface{}) (sshkeys []SshKeyConfig, count int) {
|
||||||
count = len(arg_list)
|
count = len(arg_list)
|
||||||
if count < 1 {
|
if count < 1 {
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
@@ -48,13 +47,13 @@ func makeSshKeysArgString(sshkeys []SshKeyConfig) string {
|
|||||||
// It is designed to be passed as "userdata" argument of virtual machine create API call.
|
// It is designed to be passed as "userdata" argument of virtual machine create API call.
|
||||||
// The following format is expected:
|
// The following format is expected:
|
||||||
// '{"users": [{"ssh-authorized-keys": ["SSH_PUBCIC_KEY_VALUE"], "shell": "SHELL_VALUE", "name": "USERNAME_VALUE"}, {...}, ]}'
|
// '{"users": [{"ssh-authorized-keys": ["SSH_PUBCIC_KEY_VALUE"], "shell": "SHELL_VALUE", "name": "USERNAME_VALUE"}, {...}, ]}'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
`%s\n
|
`%s\n
|
||||||
- name: %s\n
|
- name: %s\n
|
||||||
ssh-authorized-keys:
|
ssh-authorized-keys:
|
||||||
- %s\n
|
- %s\n
|
||||||
shell: /bin/bash`
|
shell: /bin/bash`
|
||||||
*/
|
*/
|
||||||
if len(sshkeys) < 1 {
|
if len(sshkeys) < 1 {
|
||||||
return ""
|
return ""
|
||||||
@@ -70,18 +69,18 @@ func makeSshKeysArgString(sshkeys []SshKeyConfig) string {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func sshSubresourceSchema() map[string]*schema.Schema {
|
func sshSubresourceSchemaMake() map[string]*schema.Schema {
|
||||||
rets := map[string]*schema.Schema {
|
rets := map[string]*schema.Schema{
|
||||||
"user": {
|
"user": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
Description: "Name of the user on the guest OS of the new VM, for which the following SSH key will be authorized.",
|
Description: "Name of the guest OS user of a new compute, for which the following SSH key will be authorized.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"public_key": {
|
"public_key": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
Description: "Public part of SSH key to authorize to the specified user on the VM being created.",
|
Description: "Public SSH key to authorize to the specified guest OS user on the compute being created.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"shell": {
|
"shell": {
|
||||||
@@ -94,4 +93,3 @@ func sshSubresourceSchema() map[string]*schema.Schema {
|
|||||||
|
|
||||||
return rets
|
return rets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user