Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c3e2c1363 |
@@ -1,7 +1,7 @@
|
|||||||
# terraform-provider-decort
|
# terraform-provider-decort
|
||||||
Terraform provider for Digital Energy Cloud Orchestration Technology (DECORT) platform
|
Terraform provider for Digital Energy Cloud Orchestration Technology (DECORT) platform
|
||||||
|
|
||||||
NOTE: provider rc-1.25 is designed for DECORT API 3.7.x. For older API versions please use:
|
NOTE: provider rc-1.30 is designed for DECORT API 3.7.x. For older API versions please use:
|
||||||
- DECORT API 3.6.x versions - provider version rc-1.10
|
- DECORT API 3.6.x versions - provider version rc-1.10
|
||||||
- DECORT API versions prior to 3.6.0 - Terraform DECS provider (https://github.com/rudecs/terraform-provider-decs)
|
- DECORT API versions prior to 3.6.0 - Terraform DECS provider (https://github.com/rudecs/terraform-provider-decs)
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
// "net/url"
|
// "net/url"
|
||||||
|
// "strconv"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@@ -151,7 +152,7 @@ func parseBootDiskId(disks []DiskRecord) uint {
|
|||||||
|
|
||||||
// Parse the list of interfaces from compute/get response into a list of networks
|
// Parse the list of interfaces from compute/get response into a list of networks
|
||||||
// attached to this compute
|
// attached to this compute
|
||||||
func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
|
func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord, pfwVinsID int, pfwRules []map[string]interface{}) []interface{} {
|
||||||
// return value will be used to d.Set("network") item of dataSourceCompute schema
|
// return value will be used to d.Set("network") item of dataSourceCompute schema
|
||||||
length := len(ifaces)
|
length := len(ifaces)
|
||||||
log.Debugf("parseComputeInterfacesToNetworks: called for %d ifaces", length)
|
log.Debugf("parseComputeInterfacesToNetworks: called for %d ifaces", length)
|
||||||
@@ -167,6 +168,14 @@ func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
|
|||||||
elem["ip_address"] = value.IPAddress
|
elem["ip_address"] = value.IPAddress
|
||||||
elem["mac"] = value.MAC
|
elem["mac"] = value.MAC
|
||||||
|
|
||||||
|
if value.NetType == "VINS" && len(pfwRules) > 0 && pfwVinsID == value.NetID {
|
||||||
|
// we have non-empty port forward rules that seem to be relevant to the current
|
||||||
|
// network segment - set "pfw_rule" element accordingly
|
||||||
|
log.Debugf("parseComputeInterfacesToNetworks: setting pfw_rule attributes on network block for ViNS ID %d",
|
||||||
|
value.NetID)
|
||||||
|
elem["pfw_rule"] = pfwRules
|
||||||
|
}
|
||||||
|
|
||||||
// log.Debugf(" element %d: net_id=%d, net_type=%s", i, value.NetID, value.NetType)
|
// log.Debugf(" element %d: net_id=%d, net_type=%s", i, value.NetID, value.NetType)
|
||||||
|
|
||||||
result = append(result, elem)
|
result = append(result, elem)
|
||||||
@@ -240,7 +249,7 @@ func parseComputeInterfaces(ifaces []InterfaceRecord) []map[string]interface{} {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func flattenCompute(d *schema.ResourceData, compFacts string) error {
|
func flattenCompute(d *schema.ResourceData, compFacts string, pfwVinsID int, pfwRules []map[string]interface{}) error {
|
||||||
// This function expects that compFacts string contains response from API compute/get,
|
// This function expects that compFacts string contains response from API compute/get,
|
||||||
// i.e. detailed information about compute instance.
|
// i.e. detailed information about compute instance.
|
||||||
//
|
//
|
||||||
@@ -283,7 +292,7 @@ func flattenCompute(d *schema.ResourceData, compFacts string) error {
|
|||||||
|
|
||||||
if len(model.Interfaces) > 0 {
|
if len(model.Interfaces) > 0 {
|
||||||
log.Debugf("flattenCompute: calling parseComputeInterfacesToNetworks for %d interfaces", len(model.Interfaces))
|
log.Debugf("flattenCompute: calling parseComputeInterfacesToNetworks for %d interfaces", len(model.Interfaces))
|
||||||
if err = d.Set("network", parseComputeInterfacesToNetworks(model.Interfaces)); err != nil {
|
if err = d.Set("network", parseComputeInterfacesToNetworks(model.Interfaces, pfwVinsID, pfwRules)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,15 +308,23 @@ func flattenCompute(d *schema.ResourceData, compFacts string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dataSourceComputeRead(d *schema.ResourceData, m interface{}) error {
|
func dataSourceComputeRead(d *schema.ResourceData, m interface{}) error {
|
||||||
compFacts, err := utilityComputeCheckPresence(d, m)
|
compID, compFacts, err := utilityComputeCheckPresence(d, m)
|
||||||
if compFacts == "" {
|
if compFacts == "" {
|
||||||
// if empty string is returned from utilityComputeCheckPresence then there is no
|
// if empty compFacts is returned from utilityComputeCheckPresence and err=nil
|
||||||
// such Compute and err tells so - just return it to the calling party
|
// it means that there is no such Compute;
|
||||||
|
// In any other case non-nil error will be reported.
|
||||||
d.SetId("") // ensure ID is empty
|
d.SetId("") // ensure ID is empty
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return flattenCompute(d, compFacts)
|
vinsID, pfwRules, err := utilityComputePfwGet(compID, m)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("dataSourceComputeRead: there was error calling utilityComputePfwGet for compute ID %s: %s",
|
||||||
|
d.Id(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenCompute(d, compFacts, vinsID, pfwRules)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataSourceCompute() *schema.Resource {
|
func dataSourceCompute() *schema.Resource {
|
||||||
|
|||||||
@@ -444,9 +444,17 @@ const AccountsListAPI = "/restmachine/cloudapi/account/list" // returns list of
|
|||||||
type AccountsListResp []AccountRecord
|
type AccountsListResp []AccountRecord
|
||||||
|
|
||||||
//
|
//
|
||||||
// structures related to /cloudapi/portforwarding/list API
|
// structures related to /cloudapi/compute/pfwlLst API
|
||||||
//
|
//
|
||||||
type PfwRecord struct {
|
|
||||||
|
// Note that if there are port forwarding rules for compute, then compute/pfwList response
|
||||||
|
// will contain a list which starts with prefix (see PfwPrefixRecord) and then contains
|
||||||
|
// one or more rule records (see PfwRuleRecord)
|
||||||
|
type PfwPrefixRecord struct {
|
||||||
|
VinsID int `json:"vinsId"`
|
||||||
|
VinsName string `json:"vinsName"`
|
||||||
|
}
|
||||||
|
type PfwRuleRecord struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
LocalIP string `json:"localIp"`
|
LocalIP string `json:"localIp"`
|
||||||
LocalPort int `json:"localPort"`
|
LocalPort int `json:"localPort"`
|
||||||
@@ -458,8 +466,6 @@ type PfwRecord struct {
|
|||||||
|
|
||||||
const ComputePfwListAPI = "/restmachine/cloudapi/compute/pfwList"
|
const ComputePfwListAPI = "/restmachine/cloudapi/compute/pfwList"
|
||||||
|
|
||||||
type ComputePfwListResp []PfwRecord
|
|
||||||
|
|
||||||
const ComputePfwAddAPI = "/restmachine/cloudapi/compute/pfwAdd"
|
const ComputePfwAddAPI = "/restmachine/cloudapi/compute/pfwAdd"
|
||||||
|
|
||||||
const ComputePfwDelAPI = "/restmachine/cloudapi/compute/pfwDel"
|
const ComputePfwDelAPI = "/restmachine/cloudapi/compute/pfwDel"
|
||||||
@@ -538,6 +544,8 @@ type VnfRecord struct {
|
|||||||
AccountID int `json:"accountId"`
|
AccountID int `json:"accountId"`
|
||||||
Type string `json:"type"` // "DHCP", "NAT", "GW" etc
|
Type string `json:"type"` // "DHCP", "NAT", "GW" etc
|
||||||
Config map[string]interface{} `json:"config"` // NOTE: VNF specs vary by VNF type
|
Config map[string]interface{} `json:"config"` // NOTE: VNF specs vary by VNF type
|
||||||
|
Status string `json:"status"`
|
||||||
|
TechStatus string `json:"techStatus"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VnfGwConfigRecord struct { // describes GW VNF config structure inside ViNS, as returned by API vins/get
|
type VnfGwConfigRecord struct { // describes GW VNF config structure inside ViNS, as returned by API vins/get
|
||||||
@@ -546,6 +554,14 @@ type VnfGwConfigRecord struct { // describes GW VNF config structure inside ViNS
|
|||||||
ExtNetMask int `json:"ext_net_mask"`
|
ExtNetMask int `json:"ext_net_mask"`
|
||||||
DefaultGW string `json:"default_gw"`
|
DefaultGW string `json:"default_gw"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NatRuleRecord struct { // describes one NAT rule, a list of such rules is maintained inside VNF NAT Config
|
||||||
|
}
|
||||||
|
type VnfNatConfigRecord struct { // describes NAT VNF config structure inside ViNS, as returned by API vins/get
|
||||||
|
Netmask int `json:"netmask"`
|
||||||
|
Network string `json:"network"` // just network address, no mask, e.g. "192.168.1.0"
|
||||||
|
Rules []NatRuleRecord `json:"rules"`
|
||||||
|
}
|
||||||
type VinsRecord struct { // represents part of the response from API vins/get
|
type VinsRecord struct { // represents part of the response from API vins/get
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ func networkSubresourceSchemaMake() map[string]*schema.Schema {
|
|||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
DiffSuppressFunc: networkSubresIPAddreDiffSupperss,
|
DiffSuppressFunc: networkSubresIPAddreDiffSupperss,
|
||||||
Description: "Optional IP address to assign to this connection. This IP should belong to the selected network and free for use.",
|
Description: "Optional IP address to assign to this connection. This IP should belong to the selected network and available for use.",
|
||||||
},
|
},
|
||||||
|
|
||||||
"mac": {
|
"mac": {
|
||||||
@@ -138,6 +138,15 @@ func networkSubresourceSchemaMake() map[string]*schema.Schema {
|
|||||||
Description: "MAC address associated with this connection. MAC address is assigned automatically.",
|
Description: "MAC address associated with this connection. MAC address is assigned automatically.",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"pfw_rule": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: pfwSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Port forwarding rule to setup for this connection. You may specify several such blocks, one for each rule.",
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
return rets
|
return rets
|
||||||
}
|
}
|
||||||
|
|||||||
70
decort/pfw_subresource.go
Normal file
70
decort/pfw_subresource.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
|
||||||
|
// "encoding/json"
|
||||||
|
// "fmt"
|
||||||
|
// "bytes"
|
||||||
|
// log "github.com/sirupsen/logrus"
|
||||||
|
// "net/url"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is subresource of network subresource of compute resource used
|
||||||
|
// when creating/managing port forwarding rules for a compute connected
|
||||||
|
// to the corresponding network
|
||||||
|
// It only applies to a ViNS connection AND to a ViNS with external network connection
|
||||||
|
|
||||||
|
func pfwSubresourceSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"pub_port_start": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, 65535),
|
||||||
|
Description: "Port number on the external interface. For a ranged rule it set the starting port number.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"pub_port_end": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, 65535),
|
||||||
|
Description: "End port number on the external interface for a ranged rule. Set it equal to start port for a single port rule.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"local_port": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, 65535),
|
||||||
|
Description: "Port number on the local interface.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"proto": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
StateFunc: stateFuncToLower,
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{"tcp", "udp"}, false),
|
||||||
|
Description: "Protocol for this rule. Could be either tcp or udp.",
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
return rets
|
||||||
|
}
|
||||||
@@ -103,7 +103,7 @@ func Provider() *schema.Provider {
|
|||||||
"decort_kvmvm": resourceCompute(),
|
"decort_kvmvm": resourceCompute(),
|
||||||
"decort_disk": resourceDisk(),
|
"decort_disk": resourceDisk(),
|
||||||
"decort_vins": resourceVins(),
|
"decort_vins": resourceVins(),
|
||||||
// "decort_pfw": resourcePfw(),
|
// "decort_k8s": resourceK8s(),
|
||||||
},
|
},
|
||||||
|
|
||||||
DataSourcesMap: map[string]*schema.Resource{
|
DataSourcesMap: map[string]*schema.Resource{
|
||||||
@@ -113,7 +113,8 @@ func Provider() *schema.Provider {
|
|||||||
"decort_image": dataSourceImage(),
|
"decort_image": dataSourceImage(),
|
||||||
"decort_disk": dataSourceDisk(),
|
"decort_disk": dataSourceDisk(),
|
||||||
"decort_vins": dataSourceVins(),
|
"decort_vins": dataSourceVins(),
|
||||||
// "decort_pfw": dataSourcePfw(),
|
// "decort_k8ci": dataSourceK8ci(),
|
||||||
|
// "decort_k8s": dataSourceK8s(),
|
||||||
},
|
},
|
||||||
|
|
||||||
ConfigureFunc: providerConfigure,
|
ConfigureFunc: providerConfigure,
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ func resourceComputeRead(d *schema.ResourceData, m interface{}) error {
|
|||||||
log.Debugf("resourceComputeRead: called for Compute name %s, RG ID %d",
|
log.Debugf("resourceComputeRead: called for Compute name %s, RG ID %d",
|
||||||
d.Get("name").(string), d.Get("rg_id").(int))
|
d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
compFacts, err := utilityComputeCheckPresence(d, m)
|
compID, compFacts, err := utilityComputeCheckPresence(d, m)
|
||||||
if compFacts == "" {
|
if compFacts == "" {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -193,7 +193,14 @@ func resourceComputeRead(d *schema.ResourceData, m interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = flattenCompute(d, compFacts); err != nil {
|
vinsID, pfwRules, err := utilityComputePfwGet(compID, m)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("resourceComputeRead: there was error calling utilityComputePfwGet for compute ID %s: %s",
|
||||||
|
d.Id(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = flattenCompute(d, compFacts, vinsID, pfwRules); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +306,7 @@ func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
|
|||||||
log.Debugf("resourceComputeDelete: called for Compute name %s, RG ID %d",
|
log.Debugf("resourceComputeDelete: called for Compute name %s, RG ID %d",
|
||||||
d.Get("name").(string), d.Get("rg_id").(int))
|
d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
compFacts, err := utilityComputeCheckPresence(d, m)
|
_, compFacts, err := utilityComputeCheckPresence(d, m)
|
||||||
if compFacts == "" {
|
if compFacts == "" {
|
||||||
// the target Compute does not exist - in this case according to Terraform best practice
|
// the target Compute does not exist - in this case according to Terraform best practice
|
||||||
// we exit from Destroy method without error
|
// we exit from Destroy method without error
|
||||||
@@ -352,7 +359,7 @@ func resourceComputeExists(d *schema.ResourceData, m interface{}) (bool, error)
|
|||||||
log.Debugf("resourceComputeExist: called for Compute name %s, RG ID %d",
|
log.Debugf("resourceComputeExist: called for Compute name %s, RG ID %d",
|
||||||
d.Get("name").(string), d.Get("rg_id").(int))
|
d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
compFacts, err := utilityComputeCheckPresence(d, m)
|
_, compFacts, err := utilityComputeCheckPresence(d, m)
|
||||||
if compFacts == "" {
|
if compFacts == "" {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@@ -145,11 +146,48 @@ func (ctrl *ControllerCfg) utilityComputeNetworksConfigure(d *schema.ResourceDat
|
|||||||
if ipSet {
|
if ipSet {
|
||||||
urlValues.Add("ipAddr", ipaddr.(string))
|
urlValues.Add("ipAddr", ipaddr.(string))
|
||||||
}
|
}
|
||||||
|
log.Debugf("utilityComputeNetworksConfigure: ready to add network type %s ID %d for Compute ID %s",
|
||||||
|
net_data["net_type"].(string), net_data["net_id"].(int), d.Id())
|
||||||
_, err := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
|
_, err := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// failed to attach network - partial resource update
|
// failed to attach network - partial resource update
|
||||||
apiErrCount++
|
apiErrCount++
|
||||||
lastSavedError = err
|
lastSavedError = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if pfw_rules, ok := net_data["pfw_rule"]; ok {
|
||||||
|
// fool-proof - port forwarding is applicable to VINS type networks only! And only to
|
||||||
|
// those ViNSes that have active GW VNF, but here we check for VINS type only, the rest
|
||||||
|
// will be validated by the cloud platform
|
||||||
|
if net_data["net_type"].(string) != "VINS" {
|
||||||
|
log.Errorf("utilityComputeNetworksConfigure: encountered port forward rules specs in network block of type %s for Compute ID %s",
|
||||||
|
net_data["net_type"].(string), d.Id())
|
||||||
|
apiErrCount++
|
||||||
|
lastSavedError = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityComputeNetworksConfigure: found port forward rules specs in network block ID %d for Compute ID %s",
|
||||||
|
net_data["net_id"].(int), d.Id())
|
||||||
|
for _, rule_runner := range pfw_rules.(*schema.Set).List() {
|
||||||
|
pfwValues := &url.Values{}
|
||||||
|
rule := rule_runner.(map[string]interface{})
|
||||||
|
pfwValues.Add("computeId", d.Id())
|
||||||
|
pfwValues.Add("publicPortStart", fmt.Sprintf("%d", rule["pub_port_start"].(int)))
|
||||||
|
pfwValues.Add("publicPortEnd", fmt.Sprintf("%d", rule["pub_port_end"].(int)))
|
||||||
|
pfwValues.Add("localBasePort", fmt.Sprintf("%d", rule["local_port"].(int)))
|
||||||
|
pfwValues.Add("proto", rule["proto"].(string))
|
||||||
|
log.Debugf("utilityComputeNetworksConfigure: ready to add pfw rule %d:%d -> %d proto %s for Compute ID %s",
|
||||||
|
rule["pub_port_start"].(int), rule["pub_port_end"].(int),
|
||||||
|
rule["proto"].(string), d.Id())
|
||||||
|
_, err := ctrl.decortAPICall("POST", ComputePfwAddAPI, pfwValues)
|
||||||
|
if err != nil {
|
||||||
|
// failed to add port forward rule - partial resource update
|
||||||
|
apiErrCount++
|
||||||
|
lastSavedError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +247,11 @@ func (ctrl *ControllerCfg) utilityComputeNetworksConfigure(d *schema.ResourceDat
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string, error) {
|
|
||||||
|
//func (ctrl *ControllerCfg) utilityComputePfwConfigure(d *schema.ResourceData, do_delta bool) error {
|
||||||
|
//}
|
||||||
|
|
||||||
|
func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (int, string, error) {
|
||||||
// This function tries to locate Compute by one of the following approaches:
|
// This function tries to locate Compute by one of the following approaches:
|
||||||
// - if compute_id is specified - locate by compute ID
|
// - if compute_id is specified - locate by compute ID
|
||||||
// - if compute_name is specified - locate by a combination of compute name and resource
|
// - if compute_name is specified - locate by a combination of compute name and resource
|
||||||
@@ -246,27 +288,27 @@ func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string,
|
|||||||
urlValues.Add("computeId", fmt.Sprintf("%d", theId))
|
urlValues.Add("computeId", fmt.Sprintf("%d", theId))
|
||||||
computeFacts, err := controller.decortAPICall("POST", ComputeGetAPI, urlValues)
|
computeFacts, err := controller.decortAPICall("POST", ComputeGetAPI, urlValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return 0, "", err
|
||||||
}
|
}
|
||||||
return computeFacts, nil
|
return theId, computeFacts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID was not set in the schema upon entering this function - work through Compute name
|
// ID was not set in the schema upon entering this function - work through Compute name
|
||||||
// and RG ID
|
// and RG ID
|
||||||
computeName, argSet := d.GetOk("name")
|
computeName, argSet := d.GetOk("name")
|
||||||
if !argSet {
|
if !argSet {
|
||||||
return "", fmt.Errorf("Cannot locate compute instance if name is empty and no compute ID specified")
|
return 0, "", fmt.Errorf("Cannot locate compute instance if name is empty and no compute ID specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
rgId, argSet := d.GetOk("rg_id")
|
rgId, argSet := d.GetOk("rg_id")
|
||||||
if !argSet {
|
if !argSet {
|
||||||
return "", fmt.Errorf("Cannot locate compute by name %s if no resource group ID is set", computeName.(string))
|
return 0, "", fmt.Errorf("Cannot locate compute by name %s if no resource group ID is set", computeName.(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
urlValues.Add("rgId", fmt.Sprintf("%d", rgId))
|
urlValues.Add("rgId", fmt.Sprintf("%d", rgId))
|
||||||
apiResp, err := controller.decortAPICall("POST", RgListComputesAPI, urlValues)
|
apiResp, err := controller.decortAPICall("POST", RgListComputesAPI, urlValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return 0, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("utilityComputeCheckPresence: ready to unmarshal string %s", apiResp)
|
log.Debugf("utilityComputeCheckPresence: ready to unmarshal string %s", apiResp)
|
||||||
@@ -274,7 +316,7 @@ func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string,
|
|||||||
computeList := RgListComputesResp{}
|
computeList := RgListComputesResp{}
|
||||||
err = json.Unmarshal([]byte(apiResp), &computeList)
|
err = json.Unmarshal([]byte(apiResp), &computeList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return 0, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// log.Printf("%#v", computeList)
|
// log.Printf("%#v", computeList)
|
||||||
@@ -288,11 +330,83 @@ func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string,
|
|||||||
cgetValues.Add("computeId", fmt.Sprintf("%d", item.ID))
|
cgetValues.Add("computeId", fmt.Sprintf("%d", item.ID))
|
||||||
apiResp, err = controller.decortAPICall("POST", ComputeGetAPI, cgetValues)
|
apiResp, err = controller.decortAPICall("POST", ComputeGetAPI, cgetValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return 0, "", err
|
||||||
}
|
}
|
||||||
return apiResp, nil
|
// NOTE: compute ID is unsigned int in the platform. Here we convert it to int, which may have
|
||||||
|
// unwanted side effects when the number of compute instances grows
|
||||||
|
return int(item.ID), apiResp, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", nil // there should be no error if Compute does not exist
|
return 0, "", nil // there should be no error if Compute does not exist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function reads port forwards from a specified compute and returns them (if any) in a
|
||||||
|
// form of a list of maps of interfaces suitable to be used for d.Set("pfw_rule") on the
|
||||||
|
// network block, corresponding to the ViNS these rules belong to. To simlify this network
|
||||||
|
// block identification among multiple blocks of the same compute this function also
|
||||||
|
// returns the ID of the ViNS associated with listed rules.
|
||||||
|
func utilityComputePfwGet(compId int, m interface{}) (int, []map[string]interface{}, error) {
|
||||||
|
// If there is an error either reading portforward rules from the cloud or parsing them, error is
|
||||||
|
// returned.
|
||||||
|
// In case there are no portforwarding rules for this compute, err = nil and rule record list is empty.
|
||||||
|
// Otherwise, both prefix record and rule record list contain meaningful data.
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
pfwPrefix := PfwPrefixRecord{}
|
||||||
|
pfwRules := []PfwRuleRecord{}
|
||||||
|
pfwRulesList := []map[string]interface{}{}
|
||||||
|
|
||||||
|
urlValues.Add("computeId", fmt.Sprintf("%d", compId))
|
||||||
|
apiResp, err := controller.decortAPICall("POST", ComputePfwListAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return 0, pfwRulesList, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiResp == "" {
|
||||||
|
// No port forward rules defined for this compute
|
||||||
|
return 0, pfwRulesList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityComputePfwGet: ready to split API response string %s", apiResp)
|
||||||
|
|
||||||
|
twoParts := strings.SplitN(apiResp, "},", 2)
|
||||||
|
if len(twoParts) != 2 {
|
||||||
|
log.Errorf("utilityComputePfwGet: non-empty pfwList response for compute ID %d failed to split into 2 fragments (got %d)", compId, len(twoParts))
|
||||||
|
return 0, pfwRulesList, fmt.Errorf("Non-empty pfwList response failed to split into 2 fragments")
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixResp := strings.TrimSuffix(strings.TrimPrefix(twoParts[0], "["), ",") + "}"
|
||||||
|
log.Debugf("utilityComputePfwGet: ready to unmarshal prefix part %s", prefixResp)
|
||||||
|
err = json.Unmarshal([]byte(prefixResp), &pfwPrefix)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("utilityComputePfwGet: failed to unmarshal prefix part of API response: %s", err)
|
||||||
|
return 0, pfwRulesList, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rulesResp := "[" + twoParts[1]
|
||||||
|
log.Debugf("utilityComputePfwGet: ready to unmarshal rules part %s", rulesResp)
|
||||||
|
err = json.Unmarshal([]byte(rulesResp), &pfwRules)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("utilityComputePfwGet: failed to unmarshal rules part of API response: %s", err)
|
||||||
|
return 0, pfwRulesList, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityComputePfwGet: successfully read %d port forward rules for Compute ID %d, ViNS ID %d",
|
||||||
|
len(pfwRules), compId, pfwPrefix.VinsID)
|
||||||
|
|
||||||
|
for _, runner := range pfwRules {
|
||||||
|
rule := map[string]interface{}{
|
||||||
|
"pub_port_start": runner.PublicPortStart,
|
||||||
|
"pub_port_end": runner.PublicPortEnd,
|
||||||
|
"local_port": runner.LocalPort,
|
||||||
|
"proto": runner.Protocol,
|
||||||
|
}
|
||||||
|
pfwRulesList = append(pfwRulesList, rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pfwPrefix.VinsID, pfwRulesList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user