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 {
|
||||
// keys in this map should correspond to the Schema definition
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -71,8 +83,22 @@ func parseComputeInterfaces(ifaces []InterfaceRecord) []interface{} {
|
||||
for i, value := range ifaces {
|
||||
// Keys in this map should correspond to the Schema definition
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -93,7 +119,7 @@ func flattenCompute(d *schema.ResourceData, comp_facts string) error {
|
||||
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.Set("compute_id", model.ID)
|
||||
@@ -119,25 +145,15 @@ func flattenCompute(d *schema.ResourceData, comp_facts string) error {
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(model.GuestLogins) > 0 {
|
||||
log.Printf("flattenCompute: calling parseGuestLogins")
|
||||
guest_logins := parseGuestLogins(model.GuestLogins)
|
||||
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 {
|
||||
log.Debugf("flattenCompute: calling parseGuestLogins for %d logins", len(model.GuestLogins))
|
||||
if err = d.Set("guest_logins", parseGuestLogins(model.GuestLogins)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -263,7 +279,7 @@ func dataSourceCompute() *schema.Resource {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource {
|
||||
Schema: interfaceSubresourceSchema(),
|
||||
Schema: interfaceSubresourceSchemaMake(),
|
||||
},
|
||||
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.")
|
||||
}
|
||||
|
||||
account_id, acc_id_set := d.GetOk("account_id")
|
||||
if !acc_id_set {
|
||||
account_name, arg_set := d.GetOkd("account_name")
|
||||
if !arg_set {
|
||||
return "", fmt.Error("Cannot locate disk by name %s if neither account ID nor account name are set", disk_name.(string))
|
||||
}
|
||||
// Valid account ID is required to locate disks
|
||||
// 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("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)
|
||||
if err != nil {
|
||||
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))
|
||||
for _, item := range disks_list {
|
||||
// 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)
|
||||
// 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>
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
@@ -34,39 +34,41 @@ import (
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
)
|
||||
|
||||
|
||||
func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
|
||||
name := d.Get("name").(string)
|
||||
rgid, rgid_set := d.GetOk("rgid")
|
||||
tenant_id, tenant_set := d.GetOk("tenant_id")
|
||||
// rg_id, rgid_set := d.GetOk("rg_id")
|
||||
account_id, account_set := d.GetOk("account_id")
|
||||
|
||||
controller := m.(*ControllerCfg)
|
||||
url_values := &url.Values{}
|
||||
if tenant_set {
|
||||
url_values.Add("accountId", fmt.Sprintf("%d",tenant_id.(int)))
|
||||
}
|
||||
if rgid_set {
|
||||
url_values.Add("cloudspaceId", fmt.Sprintf("%d",rgid.(int)))
|
||||
if account_set {
|
||||
url_values.Add("accountId", fmt.Sprintf("%d", account_id.(int)))
|
||||
}
|
||||
body_string, err := controller.decortAPICall("POST", ImagesListAPI, url_values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("dataSourceImageRead: ready to decode response body")
|
||||
log.Debugf("dataSourceImageRead: ready to decode response body from %q", ImagesListAPI)
|
||||
model := ImagesListResp{}
|
||||
err = json.Unmarshal([]byte(body_string), &model)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("%#v", model)
|
||||
log.Printf("dataSourceImageRead: traversing decoded JSON of length %d", len(model))
|
||||
// log.Printf("%#v", model)
|
||||
log.Debugf("dataSourceImageRead: traversing decoded JSON of length %d", len(model))
|
||||
for index, item := range model {
|
||||
// need to match VM by name
|
||||
// need to match Image by name
|
||||
if item.Name == 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)
|
||||
return nil
|
||||
}
|
||||
@@ -76,36 +78,67 @@ func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
|
||||
}
|
||||
|
||||
func dataSourceImage() *schema.Resource {
|
||||
return &schema.Resource {
|
||||
return &schema.Resource{
|
||||
SchemaVersion: 1,
|
||||
|
||||
Read: dataSourceImageRead,
|
||||
Read: dataSourceImageRead,
|
||||
|
||||
Timeouts: &schema.ResourceTimeout {
|
||||
Timeouts: &schema.ResourceTimeout{
|
||||
Read: &Timeout30s,
|
||||
Default: &Timeout60s,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema {
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "Name of the OS image to locate. This parameter is case sensitive.",
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "Name of the OS image to locate. This parameter is case sensitive.",
|
||||
},
|
||||
|
||||
"tenant_id": {
|
||||
"account_id": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
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": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
ValidateFunc: validation.IntAtLeast(1),
|
||||
Description: "ID of the resource group to limit image search to.",
|
||||
"arch": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "Binary architecture this image is created for.",
|
||||
},
|
||||
|
||||
"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.
|
||||
*/
|
||||
|
||||
package decs
|
||||
package decort
|
||||
|
||||
import (
|
||||
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
// "github.com/hashicorp/terraform/helper/validation"
|
||||
)
|
||||
|
||||
func flattenGuestLogins(logins []GuestLoginRecord) []interface{} {
|
||||
func parseGuestLogins(logins []OsUserRecord) []interface{} {
|
||||
var result = make([]interface{}, len(logins))
|
||||
|
||||
elem := make(map[string]interface{})
|
||||
@@ -34,28 +33,28 @@ func flattenGuestLogins(logins []GuestLoginRecord) []interface{} {
|
||||
elem["guid"] = value.Guid
|
||||
elem["login"] = value.Login
|
||||
elem["password"] = value.Password
|
||||
elem["public_key"] = value.PubKey
|
||||
result[index] = elem
|
||||
log.Printf("flattenGuestLogins: parsed element %d - login %q",
|
||||
index, value.Login)
|
||||
log.Debugf("parseGuestLogins: parsed element %d - login %q", index, value.Login)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func loginsSubresourceSchema() map[string]*schema.Schema {
|
||||
rets := map[string]*schema.Schema {
|
||||
func loginsSubresourceSchemaMake() map[string]*schema.Schema {
|
||||
rets := map[string]*schema.Schema{
|
||||
"guid": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "",
|
||||
Description: "GUID of this guest user.",
|
||||
Description: "GUID of this guest OS user.",
|
||||
},
|
||||
|
||||
"login": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "",
|
||||
Description: "Login name of this guest user.",
|
||||
Description: "Login name of this guest OS user.",
|
||||
},
|
||||
|
||||
"password": {
|
||||
@@ -63,7 +62,14 @@ func loginsSubresourceSchema() map[string]*schema.Schema {
|
||||
Optional: true,
|
||||
Default: "",
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -40,157 +38,163 @@ var Timeout180s = time.Second * 180
|
||||
// structures related to /cloudapi/rg/list API
|
||||
//
|
||||
type UserAclRecord struct {
|
||||
IsExplicit bool `json:"explicit"`
|
||||
Rights string `json:"right"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
UgroupID string `json:"userGroupId"`
|
||||
IsExplicit bool `json:"explicit"`
|
||||
Rights string `json:"right"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
UgroupID string `json:"userGroupId"`
|
||||
// CanBeDeleted bool `json:"canBeDeleted"`
|
||||
}
|
||||
|
||||
type AccountAclRecord struct {
|
||||
IsExplicit bool `json:"explicit"`
|
||||
Guid string `json:"guid"`
|
||||
Rights string `json:"right"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
UgroupID string `json:"userGroupId"`
|
||||
IsExplicit bool `json:"explicit"`
|
||||
Guid string `json:"guid"`
|
||||
Rights string `json:"right"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
UgroupID string `json:"userGroupId"`
|
||||
}
|
||||
|
||||
type ResgroupRecord struct {
|
||||
ACLs []UserAclRecord `json:"ACLs"`
|
||||
Owner AccountAclRecord `json:"accountAcl"`
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
DefaultNetID int `json:"def_net_id"`
|
||||
DefaultNetType string `json:"def_net_type"`
|
||||
Decsription string `json:"desc"`
|
||||
GridID int `json:"gid"`
|
||||
ID uint `json:"id"`
|
||||
LockStatus string `json:"lockStatus"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
UpdatedTime uint64 `json:"updatedTime"`
|
||||
Vins []int `json:"vins"`
|
||||
Computes []int `json:"vms"`
|
||||
ACLs []UserAclRecord `json:"ACLs"`
|
||||
Owner AccountAclRecord `json:"accountAcl"`
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
DefaultNetID int `json:"def_net_id"`
|
||||
DefaultNetType string `json:"def_net_type"`
|
||||
Decsription string `json:"desc"`
|
||||
GridID int `json:"gid"`
|
||||
ID uint `json:"id"`
|
||||
LockStatus string `json:"lockStatus"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
UpdatedTime uint64 `json:"updatedTime"`
|
||||
Vins []int `json:"vins"`
|
||||
Computes []int `json:"vms"`
|
||||
}
|
||||
|
||||
const ResgroupListAPI = "/restmachine/cloudapi/rg/list"
|
||||
|
||||
type ResgroupListResp []ResgroupRecord
|
||||
|
||||
//
|
||||
// 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
|
||||
//
|
||||
const ResgroupUpdateAPI= "/restmachine/cloudapi/rg/update"
|
||||
const ResgroupUpdateAPI = "/restmachine/cloudapi/rg/update"
|
||||
|
||||
type ResgroupUpdateParam struct {
|
||||
RgId int `json:"rgId"`
|
||||
Name string `json:"name"`
|
||||
Desc string `json:"decs"`
|
||||
Ram int `json:"maxMemoryCapacity"`
|
||||
Disk int `json:"maxVDiskCapacity"`
|
||||
Cpu int `json:"maxCPUCapacity"`
|
||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
RgId int `json:"rgId"`
|
||||
Name string `json:"name"`
|
||||
Desc string `json:"decs"`
|
||||
Ram int `json:"maxMemoryCapacity"`
|
||||
Disk int `json:"maxVDiskCapacity"`
|
||||
Cpu int `json:"maxCPUCapacity"`
|
||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
//
|
||||
// structures related to /cloudapi/rg/get API call
|
||||
//
|
||||
type QuotaRecord struct { // this is how quota is reported by /api/.../rg/get
|
||||
Cpu int `json:"CU_C"` // CPU count in pcs
|
||||
Ram int `json:"CU_M"` // RAM volume in MB
|
||||
Disk int `json:"CU_D"` // Disk capacity in GB
|
||||
ExtIPs int `json:"CU_I"` // Ext IPs count
|
||||
ExtTraffic int `json:"CU_NP"` // Ext network traffic
|
||||
GpuUnits int `json:"gpu_units"` // GPU count
|
||||
Cpu int `json:"CU_C"` // CPU count in pcs
|
||||
Ram int `json:"CU_M"` // RAM volume in MB
|
||||
Disk int `json:"CU_D"` // Disk capacity in GB
|
||||
ExtIPs int `json:"CU_I"` // Ext IPs count
|
||||
ExtTraffic int `json:"CU_NP"` // Ext network traffic
|
||||
GpuUnits int `json:"gpu_units"` // GPU count
|
||||
}
|
||||
|
||||
type ResourceRecord struct { // this is how actual usage is reported by /api/.../rg/get
|
||||
Cpu int `json:"cpu"`
|
||||
Disk int `json:"disksize"`
|
||||
ExtIPs int `json:"extips"`
|
||||
ExtTraffic int `json:"exttraffic"`
|
||||
Gpu int `json:"gpu"`
|
||||
Ram int `json:"ram"`
|
||||
Cpu int `json:"cpu"`
|
||||
Disk int `json:"disksize"`
|
||||
ExtIPs int `json:"extips"`
|
||||
ExtTraffic int `json:"exttraffic"`
|
||||
Gpu int `json:"gpu"`
|
||||
Ram int `json:"ram"`
|
||||
}
|
||||
|
||||
type UsageRecord struct {
|
||||
Current ResourceRecord `json:"Current"`
|
||||
Reserved ResourceRecord `json:"Reserved"`
|
||||
Current ResourceRecord `json:"Current"`
|
||||
Reserved ResourceRecord `json:"Reserved"`
|
||||
}
|
||||
|
||||
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"`
|
||||
const ResgroupGetAPI = "/restmachine/cloudapi/rg/get"
|
||||
|
||||
CreatedBy string `json:"createdBy"`
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
DefaultNetID int `json:"def_net_id"`
|
||||
DefaultNetType string `json:"def_net_type"`
|
||||
DeletedBy string `json:"deletedBy"`
|
||||
DeletedTime uint64 `json:"deletedTime"`
|
||||
Decsription string `json:"desc"`
|
||||
ID uint `json:"id"`
|
||||
LockStatus string `json:"lockStatus"`
|
||||
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"`
|
||||
type ResgroupGetResp struct {
|
||||
ACLs []UserAclRecord `json:"ACLs"`
|
||||
Usage UsageRecord `json:"Resources"`
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
|
||||
CreatedBy string `json:"createdBy"`
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
DefaultNetID int `json:"def_net_id"`
|
||||
DefaultNetType string `json:"def_net_type"`
|
||||
DeletedBy string `json:"deletedBy"`
|
||||
DeletedTime uint64 `json:"deletedTime"`
|
||||
Decsription string `json:"desc"`
|
||||
ID uint `json:"id"`
|
||||
LockStatus string `json:"lockStatus"`
|
||||
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:"-"`
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// structures related to /cloudapi/rg/update API
|
||||
//
|
||||
const ResgroupUpdateAPI = "/restmachine/cloudapi/rg/update"
|
||||
|
||||
type ResgroupUpdateParam struct {
|
||||
ID uint `json:"rgId"`
|
||||
Name string `json:"name"`
|
||||
Decsription string `json:"desc"`
|
||||
Cpu int `json:"maxCPUCapacity"`
|
||||
Ram int `json:"maxMemoryCapacity"`
|
||||
Disk int `json:"maxVDiskCapacity"`
|
||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||
ExtIPs int `json:"maxNumPublicIP"`
|
||||
Reason string `json:"reason"`
|
||||
ID uint `json:"rgId"`
|
||||
Name string `json:"name"`
|
||||
Decsription string `json:"desc"`
|
||||
Cpu int `json:"maxCPUCapacity"`
|
||||
Ram int `json:"maxMemoryCapacity"`
|
||||
Disk int `json:"maxVDiskCapacity"`
|
||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||
ExtIPs int `json:"maxNumPublicIP"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// structures related to /cloudapi/rg/delete API
|
||||
//
|
||||
const ResgroupDeleteAPI = "/restmachine/cloudapi/rg/delete"
|
||||
|
||||
//
|
||||
//
|
||||
// structures related to /cloudapi/rg/listComputes API
|
||||
//
|
||||
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
|
||||
// are really necessary to identify and distinguish computes
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
RgID int `json:"rgId"`
|
||||
RgName string `json:"rgName"`
|
||||
Status string `json:"status"`
|
||||
TechStatus string `json:"techStatus"`
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
RgID int `json:"rgId"`
|
||||
RgName string `json:"rgName"`
|
||||
Status string `json:"status"`
|
||||
TechStatus string `json:"techStatus"`
|
||||
}
|
||||
|
||||
const RgListComputesAPI = "/restmachine/cloudapi/rg/listComputes"
|
||||
|
||||
type RgListComputesResp []ComputeBriefRecord
|
||||
|
||||
//
|
||||
@@ -198,339 +202,315 @@ type RgListComputesResp []ComputeBriefRecord
|
||||
//
|
||||
const KvmX86CreateAPI = "/restmachine/cloudapi/kvmx86/create"
|
||||
const KvmPPCCreateAPI = "/restmachine/cloudapi/kvmppc/create"
|
||||
|
||||
type KvmVmCreateParam struct { // this is unified structure for both x86 and PPC based KVM VMs creation
|
||||
RgID uint `json:"rgId"`
|
||||
Name string `json:"name"`
|
||||
Cpu int `json:"cpu"`
|
||||
Ram int `json:"ram"`
|
||||
ImageID int `json:"imageId"`
|
||||
BootDisk int `json:"bootDisk"`
|
||||
NetType string `json:"netType"`
|
||||
NetId int `json:"netId"`
|
||||
IPAddr string `json:"ipAddr"`
|
||||
UserData string `json:"userdata"`
|
||||
Description string `json:"desc"`
|
||||
Start bool `json:"start"`
|
||||
RgID uint `json:"rgId"`
|
||||
Name string `json:"name"`
|
||||
Cpu int `json:"cpu"`
|
||||
Ram int `json:"ram"`
|
||||
ImageID int `json:"imageId"`
|
||||
BootDisk int `json:"bootDisk"`
|
||||
NetType string `json:"netType"`
|
||||
NetId int `json:"netId"`
|
||||
IPAddr string `json:"ipAddr"`
|
||||
UserData string `json:"userdata"`
|
||||
Description string `json:"desc"`
|
||||
Start bool `json:"start"`
|
||||
}
|
||||
|
||||
// structures related to cloudapi/compute/delete API
|
||||
const ComputeDeleteAPI = "/restmachine/cloudapi/compute/delete"
|
||||
|
||||
//
|
||||
//
|
||||
// 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 {
|
||||
ConnID int `json:"connId"`
|
||||
ConnType string `json:"connType"`
|
||||
DefaultGW string `json:"defGw"`
|
||||
Guid string `json:"guid"`
|
||||
IPAddress string `json:"ipAddress"` // without trailing network mask, i.e. "192.168.1.3"
|
||||
MAC string `json:"mac"`
|
||||
Name string `json:"name"`
|
||||
NetID int `json:"netId"`
|
||||
NetMaks int `json:"netMask"`
|
||||
NetType string `json:"netType"`
|
||||
PciSlot int `json:"pciSlot"`
|
||||
Target string `json:"target"`
|
||||
Type string `json:"type"`
|
||||
VNFs []int `json:"vnfs"`
|
||||
ConnID int `json:"connId"` // This is VLAN ID or VxLAN ID, depending on ConnType
|
||||
ConnType string `json:"connType"` // Either "VLAN" or "VXLAN" tag
|
||||
DefaultGW string `json:"defGw"`
|
||||
Guid string `json:"guid"`
|
||||
IPAddress string `json:"ipAddress"` // without trailing network mask, i.e. "192.168.1.3"
|
||||
MAC string `json:"mac"`
|
||||
Name string `json:"name"`
|
||||
NetID int `json:"netId"` // This is either ExtNet ID or ViNS ID, depending on NetType
|
||||
NetMask int `json:"netMask"`
|
||||
NetType string `json:"netType"` // Either "EXTNET" or "VINS" tag
|
||||
PciSlot int `json:"pciSlot"`
|
||||
Target string `json:"target"`
|
||||
Type string `json:"type"`
|
||||
VNFs []int `json:"vnfs"`
|
||||
QOS InterfaceQosRecord `json:"qos"`
|
||||
}
|
||||
|
||||
type SnapSetRecord struct {
|
||||
Disks []int `json:"disks"`
|
||||
Guid string `json:"guid"`
|
||||
Label string `json:"label"`
|
||||
TimeStamp uint64 `json:"timestamp"`
|
||||
Disks []int `json:"disks"`
|
||||
Guid string `json:"guid"`
|
||||
Label string `json:"label"`
|
||||
TimeStamp uint64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
type ComputeRecord struct {
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
ACLs []UserAclRecord `json:"acl"`
|
||||
Arch string `json:"arch"`
|
||||
BootDiskSize int `json:"bootdiskSize"`
|
||||
CloneReference int `json:"cloneReference"`
|
||||
Clones []int `json:"clones"`
|
||||
Cpus int `json:"cpus"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
DeletedBy string `json:"deletedBy"`
|
||||
DeletedTime uint64 `json:"deletedTime"`
|
||||
Desc string `json:"desc"`
|
||||
Disks []int `json:"disks"`
|
||||
GridID int `json:"gid"`
|
||||
ID uint `json:"id"`
|
||||
ImageID int `json:"imageId"`
|
||||
Interfaces []InterfaceRecord `json:"interfaces`
|
||||
LockStatus string `json:"lockStatus"`
|
||||
ManagerID int `json:"managerId"`
|
||||
Name string `json:"name"`
|
||||
Ram int `json:"ram"`
|
||||
RgID int `json:"rgId"`
|
||||
RgName string `json:"rgName"`
|
||||
SnapSets []SnapSetRecord `json:"snapSets"`
|
||||
Status string `json:"status"`
|
||||
Tags []string `json:"tags"`
|
||||
TechStatus string `json:"techStatus"`
|
||||
TotalDiskSize int `json:"totalDiskSize"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
UpdateTime uint64 `json:"updateTime"`
|
||||
UserManaged bool `json:"userManaged"`
|
||||
Vgpus []int `json:"vgpus"`
|
||||
VinsConnected int `json:"vinsConnected"`
|
||||
VirtualImageID int `json:"virtualImageId"`
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
ACLs []UserAclRecord `json:"acl"`
|
||||
Arch string `json:"arch"`
|
||||
BootDiskSize int `json:"bootdiskSize"`
|
||||
CloneReference int `json:"cloneReference"`
|
||||
Clones []int `json:"clones"`
|
||||
Cpus int `json:"cpus"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
CreatedTime uint64 `json:"createdTime"`
|
||||
DeletedBy string `json:"deletedBy"`
|
||||
DeletedTime uint64 `json:"deletedTime"`
|
||||
Desc string `json:"desc"`
|
||||
Disks []int `json:"disks"`
|
||||
GridID int `json:"gid"`
|
||||
ID uint `json:"id"`
|
||||
ImageID int `json:"imageId"`
|
||||
Interfaces []InterfaceRecord `json:"interfaces`
|
||||
LockStatus string `json:"lockStatus"`
|
||||
ManagerID int `json:"managerId"`
|
||||
Name string `json:"name"`
|
||||
Ram int `json:"ram"`
|
||||
RgID int `json:"rgId"`
|
||||
RgName string `json:"rgName"`
|
||||
SnapSets []SnapSetRecord `json:"snapSets"`
|
||||
Status string `json:"status"`
|
||||
Tags []string `json:"tags"`
|
||||
TechStatus string `json:"techStatus"`
|
||||
TotalDiskSize int `json:"totalDiskSize"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
UpdateTime uint64 `json:"updateTime"`
|
||||
UserManaged bool `json:"userManaged"`
|
||||
Vgpus []int `json:"vgpus"`
|
||||
VinsConnected int `json:"vinsConnected"`
|
||||
VirtualImageID int `json:"virtualImageId"`
|
||||
}
|
||||
|
||||
const ComputeListAPI = "/restmachine/cloudapi/compute/list"
|
||||
|
||||
type ComputeListResp []ComputeRecord
|
||||
|
||||
//
|
||||
// structures related to /cloudapi/compute/get
|
||||
//
|
||||
type SnapshotRecord struct {
|
||||
Guid string `json:"guid"`
|
||||
Label string `json:"label"`
|
||||
SnapSetGuid string `json:"snapSetGuid"`
|
||||
SnapSetTime uint64 `json:"snapSetTime"`
|
||||
TimeStamp uint64 `json:"timestamp"`
|
||||
Guid string `json:"guid"`
|
||||
Label string `json:"label"`
|
||||
SnapSetGuid string `json:"snapSetGuid"`
|
||||
SnapSetTime uint64 `json:"snapSetTime"`
|
||||
TimeStamp uint64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
type DiskRecord struct {
|
||||
// ACLs `json:"ACL"` - it is a dictionary, special parsing required
|
||||
// was - Acl map[string]string `json:"acl"`
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"` // NOTE: absent from compute/get output
|
||||
BootPartition int `json:"bootPartition"`
|
||||
CreatedTime uint64 `json:"creationTime"`
|
||||
DeletedTime uint64 `json:"deletionTime"`
|
||||
Desc string `json:"descr"`
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"` // NOTE: absent from compute/get output
|
||||
BootPartition int `json:"bootPartition"`
|
||||
CreatedTime uint64 `json:"creationTime"`
|
||||
DeletedTime uint64 `json:"deletionTime"`
|
||||
Desc string `json:"descr"`
|
||||
DestructionTime uint64 `json:"destructionTime"`
|
||||
DiskPath string `json:"diskPath"`
|
||||
GridID int `json:"gid"`
|
||||
ID uint `json:"id"`
|
||||
ImageID int `json:"imageId"`
|
||||
Images []int `json:"images"`
|
||||
DiskPath string `json:"diskPath"`
|
||||
GridID int `json:"gid"`
|
||||
ID uint `json:"id"`
|
||||
ImageID int `json:"imageId"`
|
||||
Images []int `json:"images"`
|
||||
// IOTune 'json:"iotune" - it is a dictionary
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name"`
|
||||
// Order `json:"order"`
|
||||
ParentId int `json:"parentId"`
|
||||
PciSlot int `json:"pciSlot"`
|
||||
ParentId int `json:"parentId"`
|
||||
PciSlot int `json:"pciSlot"`
|
||||
// ResID string `json:"resId"`
|
||||
// ResName string `json:"resName"`
|
||||
// Params string `json:"params"`
|
||||
Pool string `json:"pool"`
|
||||
PurgeTime uint64 `json:"purgeTime"`
|
||||
Pool string `json:"pool"`
|
||||
PurgeTime uint64 `json:"purgeTime"`
|
||||
// Role string `json:"role"`
|
||||
SepType string `json:"sepType"`
|
||||
SepID int `json:"sepid"`
|
||||
SizeMax int `json:"sizeMax"`
|
||||
SizeUsed int `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space
|
||||
Snapshots []SnapshotRecord `json:"snapshots"`
|
||||
Status string `json:"status"`
|
||||
TechStatus string `json:"techStatus"`
|
||||
Type string `json:"type"`
|
||||
ComputeID int `json:"vmid"`
|
||||
SepType string `json:"sepType"`
|
||||
SepID int `json:"sepid"`
|
||||
SizeMax int `json:"sizeMax"`
|
||||
SizeUsed int `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space
|
||||
Snapshots []SnapshotRecord `json:"snapshots"`
|
||||
Status string `json:"status"`
|
||||
TechStatus string `json:"techStatus"`
|
||||
Type string `json:"type"`
|
||||
ComputeID int `json:"vmid"`
|
||||
}
|
||||
|
||||
type OsUserRecord struct {
|
||||
Guid string `json:"guid"`
|
||||
Login string `json:"login"`
|
||||
Password string `json:"password"`
|
||||
PubKey string `json:"pubkey"`
|
||||
Guid string `json:"guid"`
|
||||
Login string `json:"login"`
|
||||
Password string `json:"password"`
|
||||
PubKey string `json:"pubkey"`
|
||||
}
|
||||
|
||||
const ComputeGetAPI = "/restmachine/cloudapi/compute/get"
|
||||
|
||||
type ComputeGetResp struct {
|
||||
// ACLs `json:"ACL"` - it is a dictionary, special parsing required
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
Arch string `json:"arch"`
|
||||
BootDiskSize int `json:"bootdiskSize"`
|
||||
CloneReference int `json:"cloneReference"`
|
||||
Clones []int `json:"clones"`
|
||||
Cpus int `json:"cpus"`
|
||||
Desc string `json:"desc"`
|
||||
Disks []DiskRecord `json:"disks"`
|
||||
GridID int `json:"gid"`
|
||||
ID uint `json:"id"`
|
||||
ImageID int `json:"imageId"`
|
||||
ImageName string `json:"imageName"`
|
||||
Interfaces []InterfaceRecord `json:"interfaces`
|
||||
LockStatus string `json:"lockStatus"`
|
||||
ManagerID int `json:"managerId"`
|
||||
ManagerType string `json:"manageType"`
|
||||
Name string `json:"name"`
|
||||
NatableVinsID int `json:"natableVinsId"`
|
||||
NatableVinsIP string `json:"natableVinsIp"`
|
||||
NatableVinsName string `json:"natableVinsName"`
|
||||
NatableVinsNet string `json:"natableVinsNetwork"`
|
||||
NatableVinsNetName string `json:"natableVinsNetworkName"`
|
||||
OsUsers []OsUserRecord `json:"osUsers"`
|
||||
Ram int `json:"ram"`
|
||||
RgID int `json:"rgId"`
|
||||
RgName string `json:"rgName"`
|
||||
SnapSets []SnapSetRecord `json:"snapSets"`
|
||||
Status string `json:"status"`
|
||||
Tags []string `json:"tags"`
|
||||
TechStatus string `json:"techStatus"`
|
||||
TotalDiskSize int `json:"totalDiskSize"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
UpdateTime uint64 `json:"updateTime"`
|
||||
UserManaged bool `json:"userManaged"`
|
||||
Vgpus []int `json:"vgpus"`
|
||||
VinsConnected int `json:"vinsConnected"`
|
||||
VirtualImageID int `json:"virtualImageId"`
|
||||
AccountID int `json:"accountId"`
|
||||
AccountName string `json:"accountName"`
|
||||
Arch string `json:"arch"`
|
||||
BootDiskSize int `json:"bootdiskSize"`
|
||||
CloneReference int `json:"cloneReference"`
|
||||
Clones []int `json:"clones"`
|
||||
Cpus int `json:"cpus"`
|
||||
Desc string `json:"desc"`
|
||||
Disks []DiskRecord `json:"disks"`
|
||||
GridID int `json:"gid"`
|
||||
ID uint `json:"id"`
|
||||
ImageID int `json:"imageId"`
|
||||
ImageName string `json:"imageName"`
|
||||
Interfaces []InterfaceRecord `json:"interfaces`
|
||||
LockStatus string `json:"lockStatus"`
|
||||
ManagerID int `json:"managerId"`
|
||||
ManagerType string `json:"manageType"`
|
||||
Name string `json:"name"`
|
||||
NatableVinsID int `json:"natableVinsId"`
|
||||
NatableVinsIP string `json:"natableVinsIp"`
|
||||
NatableVinsName string `json:"natableVinsName"`
|
||||
NatableVinsNet string `json:"natableVinsNetwork"`
|
||||
NatableVinsNetName string `json:"natableVinsNetworkName"`
|
||||
OsUsers []OsUserRecord `json:"osUsers"`
|
||||
Ram int `json:"ram"`
|
||||
RgID int `json:"rgId"`
|
||||
RgName string `json:"rgName"`
|
||||
SnapSets []SnapSetRecord `json:"snapSets"`
|
||||
Status string `json:"status"`
|
||||
Tags []string `json:"tags"`
|
||||
TechStatus string `json:"techStatus"`
|
||||
TotalDiskSize int `json:"totalDiskSize"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
UpdateTime uint64 `json:"updateTime"`
|
||||
UserManaged bool `json:"userManaged"`
|
||||
Vgpus []int `json:"vgpus"`
|
||||
VinsConnected int `json:"vinsConnected"`
|
||||
VirtualImageID int `json:"virtualImageId"`
|
||||
}
|
||||
|
||||
//
|
||||
// structures related to /restmachine/cloudapi/images/list API
|
||||
//
|
||||
type ImageRecord struct {
|
||||
AccountID uint `json:"accountId"`
|
||||
Arch string `json:"architecture`
|
||||
BootType string `json:"bootType"`
|
||||
IsBootable boo `json:"bootable"`
|
||||
IsCdrom bool `json:"cdrom"`
|
||||
Desc string `json:"description"`
|
||||
IsHotResize bool `json:"hotResize"`
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Pool string `json:"pool"`
|
||||
SepID int `json:"sepid"`
|
||||
Size int `json:"size"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
Username string `json:"username"`
|
||||
IsVirtual bool `json:"virtual"`
|
||||
AccountID uint `json:"accountId"`
|
||||
Arch string `json:"architecture`
|
||||
BootType string `json:"bootType"`
|
||||
IsBootable bool `json:"bootable"`
|
||||
IsCdrom bool `json:"cdrom"`
|
||||
Desc string `json:"description"`
|
||||
IsHotResize bool `json:"hotResize"`
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Pool string `json:"pool"`
|
||||
SepID int `json:"sepid"`
|
||||
Size int `json:"size"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
Username string `json:"username"`
|
||||
IsVirtual bool `json:"virtual"`
|
||||
}
|
||||
|
||||
const ImagesListAPI = "/restmachine/cloudapi/images/list"
|
||||
type ImagesListParam struct {
|
||||
AccountID int `json:"accountId"`
|
||||
}
|
||||
|
||||
type ImagesListResp []ImageRecord
|
||||
|
||||
//
|
||||
// structures related to /cloudapi/extnet/list API
|
||||
//
|
||||
type ExtNetRecord struct {
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
IPCIDR string `json:"ipcidr"`
|
||||
}
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
IPCIDR string `json:"ipcidr"`
|
||||
}
|
||||
|
||||
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
|
||||
//
|
||||
type AccountRecord struct {
|
||||
ACLs []UserAclRecord `json:"acl"`
|
||||
CreatedTime uint64 `json:"creationTime"`
|
||||
DeletedTime uint64 `json:"deletionTime"`
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
UpdatedTime uint64 `json:"updateTime"`
|
||||
// ACLs []UserAclRecord `json:"acl"`
|
||||
// CreatedTime uint64 `json:"creationTime"`
|
||||
// DeletedTime uint64 `json:"deletionTime"`
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
// 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
|
||||
|
||||
//
|
||||
// structures related to /cloudapi/portforwarding/list API
|
||||
//
|
||||
type PfwRecord struct {
|
||||
ID int `json:"id"`
|
||||
LocalIP string `json:"localIp`
|
||||
LocalPort int `json:"localPort"`
|
||||
Protocol string `json:"protocol"`
|
||||
PublicPortEnd int `json:"publicPortEnd"`
|
||||
ID int `json:"id"`
|
||||
LocalIP string `json:"localIp`
|
||||
LocalPort int `json:"localPort"`
|
||||
Protocol string `json:"protocol"`
|
||||
PublicPortEnd int `json:"publicPortEnd"`
|
||||
PublicPortStart int `json:"publicPortStart"`
|
||||
ComputeID int `json:"vmId"`
|
||||
}
|
||||
ComputeID int `json:"vmId"`
|
||||
}
|
||||
|
||||
const ComputePfwListAPI = "/restmachine/cloudapi/compute/pfwList"
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
|
||||
//
|
||||
// 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"
|
||||
|
||||
type ComputeNetDetachParam struct {
|
||||
ComputeID int `json:"computeId"`
|
||||
IPAddr string `json:"apAddr"`
|
||||
MAC string `json:"mac"`
|
||||
}
|
||||
const ComputeNetDetachAPI = "/restmachine/cloudapi/compute/netDetach"
|
||||
|
||||
|
||||
//
|
||||
// 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 ComputeDiskDetachAPI = "/restmachine/cloudapi/compute/diskDetach"
|
||||
|
||||
//
|
||||
// structures related to /cloudapi/disks/create
|
||||
//
|
||||
//
|
||||
type DiskCreateParam struct {
|
||||
AccountID int `json:"accountId`
|
||||
GridID int `json:"gid"`
|
||||
Name string `json:"string"`
|
||||
Description string `json:"description"`
|
||||
Size int `json:"size"`
|
||||
Type string `json:"type"`
|
||||
SepID int `json:"sep_id"`
|
||||
Pool string `json:"pool"`
|
||||
AccountID int `json:"accountId`
|
||||
GridID int `json:"gid"`
|
||||
Name string `json:"string"`
|
||||
Description string `json:"description"`
|
||||
Size int `json:"size"`
|
||||
Type string `json:"type"`
|
||||
SepID int `json:"sep_id"`
|
||||
Pool string `json:"pool"`
|
||||
}
|
||||
|
||||
const DiskCreateAPI = "/restmachine/cloudapi/disks/create"
|
||||
|
||||
//
|
||||
// structures related to /cloudapi/disks/get
|
||||
//
|
||||
type DisksGetParam struct {
|
||||
DiskID int `json:"diskId`
|
||||
}
|
||||
//
|
||||
const DisksCreateAPI = "/restmachine/cloudapi/disks/create"
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
// "github.com/hashicorp/terraform/terraform"
|
||||
|
||||
)
|
||||
|
||||
var decsController *ControllerCfg
|
||||
|
||||
func Provider() *schema.Provider {
|
||||
return &schema.Provider {
|
||||
Schema: map[string]*schema.Schema {
|
||||
return &schema.Provider{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"authenticator": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
StateFunc: stateFuncToLower,
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
StateFunc: stateFuncToLower,
|
||||
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": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
StateFunc: stateFuncToLower,
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECS_OAUTH2_URL", nil),
|
||||
Description: "The Oauth2 application URL in 'oauth2' authentication mode.",
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECORT_OAUTH2_URL", nil),
|
||||
Description: "OAuth2 application URL in 'oauth2' authentication mode.",
|
||||
},
|
||||
|
||||
"controller_url": {
|
||||
@@ -53,67 +51,70 @@ func Provider() *schema.Provider {
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
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": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECS_USER", nil),
|
||||
Description: "The user name for DECS cloud API operations in 'legacy' authentication mode.",
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECORT_USER", nil),
|
||||
Description: "User name for DECORT cloud API operations in 'legacy' authentication mode.",
|
||||
},
|
||||
|
||||
"password": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECS_PASSWORD", nil),
|
||||
Description: "The user password for DECS cloud API operations in 'legacy' authentication mode.",
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECORT_PASSWORD", nil),
|
||||
Description: "User password for DECORT cloud API operations in 'legacy' authentication mode.",
|
||||
},
|
||||
|
||||
"app_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECS_APP_ID", nil),
|
||||
Description: "Application ID to access DECS cloud API in 'oauth2' authentication mode.",
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECORT_APP_ID", nil),
|
||||
Description: "Application ID to access DECORT cloud API in 'oauth2' authentication mode.",
|
||||
},
|
||||
|
||||
"app_secret": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECS_APP_SECRET", nil),
|
||||
Description: "Application secret to access DECS cloud API in 'oauth2' authentication mode.",
|
||||
DefaultFunc: schema.EnvDefaultFunc("DECSORTAPP_SECRET", nil),
|
||||
Description: "Application secret to access DECORT cloud API in 'oauth2' authentication mode.",
|
||||
},
|
||||
|
||||
"jwt": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
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": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
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_kvmx86": resourceKvmX86(),
|
||||
"decort_disk": resourceDisk(),
|
||||
"decort_vins": resourceVins(),
|
||||
"decort_kvmvm": resourceCompute(),
|
||||
"decort_disk": resourceDisk(),
|
||||
"decort_vins": resourceVins(),
|
||||
// "decort_pfw": resourcePfw(),
|
||||
},
|
||||
|
||||
DataSourcesMap: map[string]*schema.Resource {
|
||||
DataSourcesMap: map[string]*schema.Resource{
|
||||
// "decort_account": dataSourceAccount(),
|
||||
"decort_resgroup": dataSourceResgroup(),
|
||||
"decs_kvmx86": dataSourceCompute(),
|
||||
"decort_image": dataSourceImage(),
|
||||
"decort_disk": dataSourceDisk(),
|
||||
"decort_vins": dataSourceVins(),
|
||||
"decort_kvmvm": dataSourceCompute(),
|
||||
"decort_image": dataSourceImage(),
|
||||
"decort_disk": dataSourceDisk(),
|
||||
"decort_vins": dataSourceVins(),
|
||||
// "decort_pfw": dataSourcePfw(),
|
||||
},
|
||||
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
}
|
||||
}
|
||||
@@ -128,4 +129,4 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
// "net/url"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
// "github.com/hashicorp/terraform/helper/validation"
|
||||
|
||||
)
|
||||
|
||||
func flattenResgroup(d *schema.ResourceData, rg_facts string) error {
|
||||
// NOTE: this function modifies ResourceData argument - as such it should never be called
|
||||
// from resourceRsgroupExists(...) method
|
||||
log.Debugf("%s", rg_facts)
|
||||
log.Debugf("flattenResgroup: ready to decode response body from %q", CloudspacesGetAPI)
|
||||
// log.Debugf("%s", rg_facts)
|
||||
log.Debugf("flattenResgroup: ready to decode response body from API")
|
||||
details := ResgroupGetResp{}
|
||||
err := json.Unmarshal([]byte(rg_facts), &details)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("flattenResgroup: decoded ResGroup name %q / ID %d, account ID %d, public IP %q",
|
||||
details.Name, details.ID, details.AccountID, details.PublicIP)
|
||||
log.Debugf("flattenResgroup: decoded RG name %q / ID %d, account ID %d",
|
||||
details.Name, details.ID, details.AccountID)
|
||||
|
||||
d.SetId(fmt.Sprintf("%d", details.ID))
|
||||
d.Set("rg_id", details.ID)
|
||||
d.Set("name", details.Name)
|
||||
d.Set("account_name", details.AccountName)
|
||||
d.Set("account_id", details.AccountID)
|
||||
d.Set("grid_id", details.GridID)
|
||||
d.Set("desc", details.Description)
|
||||
@@ -73,7 +74,7 @@ func dataSourceResgroupRead(d *schema.ResourceData, m interface{}) error {
|
||||
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||
if rg_facts == "" {
|
||||
// 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
|
||||
return err
|
||||
}
|
||||
@@ -81,92 +82,97 @@ func dataSourceResgroupRead(d *schema.ResourceData, m interface{}) error {
|
||||
return flattenResgroup(d, rg_facts)
|
||||
}
|
||||
|
||||
|
||||
func dataSourceResgroup() *schema.Resource {
|
||||
return &schema.Resource {
|
||||
return &schema.Resource{
|
||||
SchemaVersion: 1,
|
||||
|
||||
Read: dataSourceResgroupRead,
|
||||
Read: dataSourceResgroupRead,
|
||||
|
||||
Timeouts: &schema.ResourceTimeout {
|
||||
Timeouts: &schema.ResourceTimeout{
|
||||
Read: &Timeout30s,
|
||||
Default: &Timeout60s,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema {
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "Name of this resource group. Names are case sensitive and unique within the context of an account.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
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,
|
||||
Required: true,
|
||||
Required: Optional,
|
||||
Description: "Name of the account, which this resource group belongs to.",
|
||||
},
|
||||
|
||||
"account_id": &schema.Schema {
|
||||
"account_id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "Unique ID of the account, which this resource group belongs to.",
|
||||
Optional: Optional,
|
||||
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,
|
||||
Computed: true,
|
||||
Description: "User-defined text description of this resource group.",
|
||||
},
|
||||
|
||||
"grid_id": &schema.Schema {
|
||||
"grid_id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "Unique ID of the grid, where this resource group is deployed.",
|
||||
},
|
||||
|
||||
"quotas": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource {
|
||||
Schema: quotaRgSubresourceSchema(), // this is a dictionary
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource{
|
||||
Schema: quotaRgSubresourceSchema(), // this is a dictionary
|
||||
},
|
||||
Description: "Quotas on the resources for this resource group.",
|
||||
},
|
||||
|
||||
"status": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "Current status of this resource group.",
|
||||
"status": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "Current status of this resource group.",
|
||||
},
|
||||
|
||||
"def_net": &schema.Schema {
|
||||
"def_net": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "Type of the default network for this resource group.",
|
||||
},
|
||||
|
||||
"def_net_id": &schema.Schema {
|
||||
"def_net_id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "ID of the default network for this resource group (if any).",
|
||||
},
|
||||
|
||||
"vins": {
|
||||
Type: schema.TypeList, // this is a list of ints
|
||||
Computed: true,
|
||||
MaxItems: LimitMaxVinsPerResgroup,
|
||||
Elem: &schema.Schema {
|
||||
Type: schema.TypeInt,
|
||||
Type: schema.TypeList, // this is a list of ints
|
||||
Computed: true,
|
||||
MaxItems: LimitMaxVinsPerResgroup,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
Description: "List of VINs deployed in this resource group.",
|
||||
},
|
||||
|
||||
"computes": {
|
||||
Type: schema.TypeList, //t his is a list of ints
|
||||
Computed: true,
|
||||
Elem: &schema.Schema {
|
||||
Type: schema.TypeInt,
|
||||
Type: schema.TypeList, //t his is a list of ints
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
|
||||
// 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
|
||||
// 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 {
|
||||
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
|
||||
set_quota := false
|
||||
var quota_record QuotaRecord
|
||||
var quota_record QuotaRecord
|
||||
arg_value, arg_set = d.GetOk("quota")
|
||||
if arg_set {
|
||||
log.Debugf("resourceResgroupCreate: setting Quota on RG requested")
|
||||
@@ -75,34 +69,34 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
|
||||
|
||||
controller := m.(*ControllerCfg)
|
||||
log.Debugf("resourceResgroupCreate: called by user %q for RG name %q, account %q / ID %d, Grid ID %d",
|
||||
controller.getdecortUsername(),
|
||||
rg_name.(string), account_name.(string), validated_account_id, gird_id.(int))
|
||||
controller.getdecortUsername(),
|
||||
rg_name.(string), account_name.(string), validated_account_id, gird_id.(int))
|
||||
/*
|
||||
type ResgroupCreateParam struct {
|
||||
AccountID int `json:"accountId"`
|
||||
GridId int `json:"gid"`
|
||||
Name string `json:"name"`
|
||||
Ram int `json:"maxMemoryCapacity"`
|
||||
Disk int `json:"maxVDiskCapacity"`
|
||||
Cpu int `json:"maxCPUCapacity"`
|
||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||
ExtIPs int `json:"maxNumPublicIP"`
|
||||
Owner string `json:"owner"`
|
||||
DefNet string `json:"def_net"`
|
||||
IPCidr string `json:"ipcidr"`
|
||||
Desc string `json:"decs"`
|
||||
Reason string `json:"reason"`
|
||||
ExtNetID int `json:"extNetId"`
|
||||
ExtIP string `json:"extIp"`
|
||||
}
|
||||
type ResgroupCreateParam struct {
|
||||
AccountID int `json:"accountId"`
|
||||
GridId int `json:"gid"`
|
||||
Name string `json:"name"`
|
||||
Ram int `json:"maxMemoryCapacity"`
|
||||
Disk int `json:"maxVDiskCapacity"`
|
||||
Cpu int `json:"maxCPUCapacity"`
|
||||
NetTraffic int `json:"maxNetworkPeerTransfer"`
|
||||
ExtIPs int `json:"maxNumPublicIP"`
|
||||
Owner string `json:"owner"`
|
||||
DefNet string `json:"def_net"`
|
||||
IPCidr string `json:"ipcidr"`
|
||||
Desc string `json:"decs"`
|
||||
Reason string `json:"reason"`
|
||||
ExtNetID int `json:"extNetId"`
|
||||
ExtIP string `json:"extIp"`
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
url_values := &url.Values{}
|
||||
url_values.Add("accountId", fmt.Sprintf("%d", validated_account_id))
|
||||
url_values.Add("name", rg_name.(string))
|
||||
url_values.Add("gid", fmt.Sprintf("%d", grid_id.(int)))
|
||||
url_values.Add("owner", controller.getdecortUsername())
|
||||
|
||||
|
||||
// pass quota values as set
|
||||
if set_quota {
|
||||
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 {
|
||||
ulr_values.Add("extIp", ext_ip.(string))
|
||||
}
|
||||
|
||||
|
||||
api_resp, err := controller.decortAPICall("POST", ResgroupCreateAPI, url_values)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -147,12 +141,12 @@ func resourceResgroupCreate(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",
|
||||
d.Get("name").(string), d.Get("account").(string))
|
||||
log.Debugf("resourceResgroupRead: called for RG name %q, account name %q",
|
||||
d.Get("name").(string), d.Get("account_name").(string))
|
||||
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||
if rg_facts == "" {
|
||||
// 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
|
||||
return err
|
||||
}
|
||||
@@ -161,8 +155,8 @@ func resourceResgroupRead(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",
|
||||
d.Get("name").(string), d.Get("account").(string))
|
||||
log.Debugf("resourceResgroupUpdate: called for RG name %q, account name %q",
|
||||
d.Get("name").(string), d.Get("account").(string))
|
||||
|
||||
do_update := false
|
||||
|
||||
@@ -179,7 +173,7 @@ func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
|
||||
url_values.Add("name", name_new.(string))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
quota_value, quota_set := d.GetOk("quota")
|
||||
if quota_set {
|
||||
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)
|
||||
url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quotarecord_new.Cpu))
|
||||
}
|
||||
|
||||
|
||||
if quotarecord_new.Disk != quotarecord_old.Disk {
|
||||
do_update = true
|
||||
log.Debugf("resourceResgroupUpdate: Disk diff %d <- %d", quotarecord_new.Disk, quotarecord_old.Disk)
|
||||
url_values.Add("maxVDiskCapacity", fmt.Sprintf("%d", quotarecord_new.Disk))
|
||||
}
|
||||
|
||||
|
||||
if quotarecord_new.Ram != quotarecord_old.Ram {
|
||||
do_update = true
|
||||
log.Debugf("resourceResgroupUpdate: Ram diff %f <- %f", quotarecord_new.Ram, quotarecord_old.Ram)
|
||||
url_values.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotarecord_new.Ram))
|
||||
}
|
||||
|
||||
|
||||
if quotarecord_new.ExtTraffic != quotarecord_old.ExtTraffic {
|
||||
do_update = true
|
||||
log.Debugf("resourceResgroupUpdate: NetTraffic diff %d <- %d", quotarecord_new.ExtTraffic, quotarecord_old.ExtTraffic)
|
||||
url_values.Add("maxNetworkPeerTransfer", fmt.Sprintf("%d", quotarecord_new.NetTraffic))
|
||||
}
|
||||
|
||||
|
||||
if quotarecord_new.ExtIPs != quotarecord_old.ExtIPs {
|
||||
do_update = true
|
||||
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 {
|
||||
log.Debugf("resourceResgroupUpdate: no difference between old and new state - no update on the RG will be done")
|
||||
}
|
||||
|
||||
|
||||
return resourceResgroupRead(d, m)
|
||||
}
|
||||
|
||||
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
|
||||
// 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",
|
||||
d.Get("name").(string), d.Get("account").(string))
|
||||
log.Debugf("resourceResgroupDelete: called for RG name %q, account name %q",
|
||||
d.Get("name").(string), d.Get("account_name").(string))
|
||||
|
||||
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||
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
|
||||
return nil
|
||||
}
|
||||
@@ -282,7 +276,7 @@ func resourceResgroupExists(d *schema.ResourceData, m interface{}) (bool, error)
|
||||
}
|
||||
|
||||
func resourceResgroup() *schema.Resource {
|
||||
return &schema.Resource {
|
||||
return &schema.Resource{
|
||||
SchemaVersion: 1,
|
||||
|
||||
Create: resourceResgroupCreate,
|
||||
@@ -291,7 +285,7 @@ func resourceResgroup() *schema.Resource {
|
||||
Delete: resourceResgroupDelete,
|
||||
Exists: resourceResgroupExists,
|
||||
|
||||
Timeouts: &schema.ResourceTimeout {
|
||||
Timeouts: &schema.ResourceTimeout{
|
||||
Create: &Timeout180s,
|
||||
Read: &Timeout30s,
|
||||
Update: &Timeout180s,
|
||||
@@ -299,103 +293,109 @@ func resourceResgroup() *schema.Resource {
|
||||
Default: &Timeout60s,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema {
|
||||
"name": &schema.Schema {
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
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,
|
||||
Required: true,
|
||||
Optional: true,
|
||||
Description: "Name of the account, which this resource group belongs to.",
|
||||
},
|
||||
|
||||
"def_net": &schema.Schema {
|
||||
"def_net": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
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.",
|
||||
},
|
||||
|
||||
"ipcidr": &schema.Schema {
|
||||
"ipcidr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
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,
|
||||
Optional: true,
|
||||
Default: 0,
|
||||
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,
|
||||
Optional: true,
|
||||
Description: "IP address on the external netowrk to request, if def_net=PUBLIC",
|
||||
},
|
||||
|
||||
"account_id": &schema.Schema {
|
||||
"account_id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "Unique ID of the account, which this resource group belongs to.",
|
||||
},
|
||||
|
||||
"grid_id": &schema.Schema {
|
||||
"grid_id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
Description: "Unique ID of the grid, where this resource group is deployed.",
|
||||
},
|
||||
|
||||
"quota": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource {
|
||||
Schema: quotasSubresourceSchema(),
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource{
|
||||
Schema: quotasSubresourceSchema(),
|
||||
},
|
||||
Description: "Quota settings for this resource group.",
|
||||
},
|
||||
|
||||
"desc": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "User-defined text description of this resource group.",
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "User-defined text description of this resource group.",
|
||||
},
|
||||
|
||||
"status": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "Current status of this resource group.",
|
||||
"status": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Description: "Current status of this resource group.",
|
||||
},
|
||||
|
||||
"def_net_id": &schema.Schema {
|
||||
"def_net_id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Description: "ID of the default network for this resource group (if any).",
|
||||
},
|
||||
|
||||
"vins": {
|
||||
Type: schema.TypeList, // this is a list of ints
|
||||
Computed: true,
|
||||
MaxItems: LimitMaxVinsPerResgroup,
|
||||
Elem: &schema.Schema {
|
||||
Type: schema.TypeInt,
|
||||
Type: schema.TypeList, // this is a list of ints
|
||||
Computed: true,
|
||||
MaxItems: LimitMaxVinsPerResgroup,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
Description: "List of VINs deployed in this resource group.",
|
||||
},
|
||||
|
||||
"computes": {
|
||||
Type: schema.TypeList, // this is a list of ints
|
||||
Computed: true,
|
||||
Elem: &schema.Schema {
|
||||
Type: schema.TypeInt,
|
||||
Type: schema.TypeList, // this is a list of ints
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
},
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
|
||||
// "strconv"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
@@ -52,18 +52,18 @@ func (ctrl *ControllerCfg) utilityResgroupConfigGet(rgid int) (*ResgroupGetResp,
|
||||
}
|
||||
|
||||
/*
|
||||
ret := &ResgroupConfig{}
|
||||
ret.AccountID = model.AccountID
|
||||
ret.Location = model.Location
|
||||
ret.Name = model.Name
|
||||
ret.ID = rgid
|
||||
ret.GridID = model.GridID
|
||||
ret.ExtIP = model.ExtIP // legacy field for VDC - this will eventually become obsoleted by true Resource Groups
|
||||
// Quota ResgroupQuotaConfig
|
||||
// Network NetworkConfig
|
||||
ret := &ResgroupConfig{}
|
||||
ret.AccountID = model.AccountID
|
||||
ret.Location = model.Location
|
||||
ret.Name = model.Name
|
||||
ret.ID = rgid
|
||||
ret.GridID = model.GridID
|
||||
ret.ExtIP = model.ExtIP // legacy field for VDC - this will eventually become obsoleted by true Resource Groups
|
||||
// Quota ResgroupQuotaConfig
|
||||
// Network NetworkConfig
|
||||
*/
|
||||
log.Debugf("utilityResgroupConfigGet: account ID %d, GridID %d, Name %s",
|
||||
model.AccountID, model.GridID, model.Name)
|
||||
log.Debugf("utilityResgroupConfigGet: account ID %d, GridID %d, Name %s",
|
||||
model.AccountID, model.GridID, model.Name)
|
||||
|
||||
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
|
||||
// into ResgroupGetResp structure
|
||||
func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string, error) {
|
||||
// This function tries to locate resource group by its name and account name.
|
||||
// If succeeded, it returns non empty string that contains JSON formatted facts about the
|
||||
// This function tries to locate resource group by one of the following algorithms depending
|
||||
// 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.
|
||||
// Otherwise it returns empty string and meaningful error.
|
||||
//
|
||||
// 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
|
||||
// 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
|
||||
// .../rg/list API with includedeleted=false
|
||||
//
|
||||
// This function does not modify its ResourceData argument, so it is safe to use it as core
|
||||
// method for the Terraform resource Exists method.
|
||||
//
|
||||
name := d.Get("name").(string)
|
||||
account_name := d.Get("account").(string)
|
||||
|
||||
controller := m.(*ControllerCfg)
|
||||
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")
|
||||
body_string, err := controller.decortAPICall("POST", ResgroupListAPI, url_values)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Debugf("%s", body_string)
|
||||
log.Debugf("utilityResgroupCheckPresence: ready to decode response body from %q", ResgroupListAPI)
|
||||
// log.Debugf("%s", body_string)
|
||||
// log.Debugf("utilityResgroupCheckPresence: ready to decode response body from %q", ResgroupListAPI)
|
||||
model := ResgroupListResp{}
|
||||
err = json.Unmarshal([]byte(body_string), &model)
|
||||
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))
|
||||
for index, item := range model {
|
||||
// need to match RG by name & account name
|
||||
if item.Name == name && item.AccountName == account_name {
|
||||
log.Debugf("utilityResgroupCheckPresence: match RG name %q / ID %d, account %q at index %d",
|
||||
item.Name, item.ID, item.AccountName, index)
|
||||
// match by RG name & account ID
|
||||
if item.Name == rg_name.(string) && item.AccountID == validated_account_id {
|
||||
log.Debugf("utilityResgroupCheckPresence: match RG name %q / ID %d, account ID %d at index %d",
|
||||
item.Name, item.ID, item.AccountID, index)
|
||||
|
||||
// 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.
|
||||
// Namely, we need to extract resource quota settings
|
||||
req_values := &url.Values{}
|
||||
// Namely, we need resource quota settings
|
||||
req_values := &url.Values{}
|
||||
req_values.Add("rgId", fmt.Sprintf("%d", item.ID))
|
||||
body_string, err := controller.decortAPICall("POST", ResgroupGetAPI, req_values)
|
||||
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>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package decs
|
||||
package decort
|
||||
|
||||
import (
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
@@ -26,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
func makeSshKeysConfig(arg_list []interface{}) (sshkeys []SshKeyConfig, count int) {
|
||||
count = len(arg_list)
|
||||
count = len(arg_list)
|
||||
if count < 1 {
|
||||
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.
|
||||
// The following format is expected:
|
||||
// '{"users": [{"ssh-authorized-keys": ["SSH_PUBCIC_KEY_VALUE"], "shell": "SHELL_VALUE", "name": "USERNAME_VALUE"}, {...}, ]}'
|
||||
|
||||
|
||||
/*
|
||||
`%s\n
|
||||
- name: %s\n
|
||||
ssh-authorized-keys:
|
||||
- %s\n
|
||||
shell: /bin/bash`
|
||||
`%s\n
|
||||
- name: %s\n
|
||||
ssh-authorized-keys:
|
||||
- %s\n
|
||||
shell: /bin/bash`
|
||||
*/
|
||||
if len(sshkeys) < 1 {
|
||||
return ""
|
||||
@@ -70,18 +69,18 @@ func makeSshKeysArgString(sshkeys []SshKeyConfig) string {
|
||||
return out
|
||||
}
|
||||
|
||||
func sshSubresourceSchema() map[string]*schema.Schema {
|
||||
rets := map[string]*schema.Schema {
|
||||
func sshSubresourceSchemaMake() map[string]*schema.Schema {
|
||||
rets := map[string]*schema.Schema{
|
||||
"user": {
|
||||
Type: schema.TypeString,
|
||||
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": {
|
||||
Type: schema.TypeString,
|
||||
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": {
|
||||
@@ -94,4 +93,3 @@ func sshSubresourceSchema() map[string]*schema.Schema {
|
||||
|
||||
return rets
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user