Improve stability of PFW check presence method

rc-1.40
Sergey Shubin svs1370 3 years ago
parent 105273af48
commit a5f6c60a71

@ -130,6 +130,7 @@ func dataSourcePfw() *schema.Resource {
Description: "ID of the ViNS to configure port forwarding rules on. Compute must be already plugged into this ViNS and ViNS must have external network connection.", Description: "ID of the ViNS to configure port forwarding rules on. Compute must be already plugged into this ViNS and ViNS must have external network connection.",
}, },
// TODO: consider making "rule" attribute Required with MinItems = 1
"rule": { "rule": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,

@ -197,6 +197,8 @@ func resourcePfw() *schema.Resource {
Description: "ID of the ViNS to configure port forwarding rules on. Compute must be already plugged into this ViNS and ViNS must have external network connection.", Description: "ID of the ViNS to configure port forwarding rules on. Compute must be already plugged into this ViNS and ViNS must have external network connection.",
}, },
// TODO: consider making "rule" attribute Required with MinItems = 1 to prevent
// empty PFW list definition
"rule": { "rule": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,

@ -42,24 +42,40 @@ func utilityPfwCheckPresence(d *schema.ResourceData, m interface{}) (string, err
// method for the Terraform resource Exists method. // method for the Terraform resource Exists method.
// //
// The string returned by this method mimics response of an imaginary API that will
// report PFW rules (if any) as following:
// {
// "header": {
// "computeId": <int>,
// "vinsId": <int>,
// },
// "rules": [
// {
// "id": <int>,
// "localPort": <int>,
// "protocol": <int>,
// "publicPortStart": <int>,
// "publicPortEnd": <int>,
// "vmId": <int>,
// },
// {
// ...
// },
// ],
// }
// This response unmarshalls into ComputePfwListResp structure.
// NOTE: If there are no rules for this compute, an empty string is returned along with err=nil
//
controller := m.(*ControllerCfg) controller := m.(*ControllerCfg)
urlValues := &url.Values{} urlValues := &url.Values{}
// NOTE on importing PFW into TF state resource:
//
// Port forward rules are NOT represented by any "individual" resource in the platform.
// Consequently, there is no unique ID reported by the platform that could be used to
// identify PFW rule set.
// However, we need some ID to identify PFW resource in TF state, and compute ID is the most
// convenient way, as it is:
// 1) unique;
// 2) compute may have only one PFW rule set.
//
var compId, vinsId int var compId, vinsId int
// PFW resource ID is a combination of compute_id and vins_id separated by ":"
// See a note in "flattenPfw" method explaining the rationale behind this approach.
if d.Id() != "" { if d.Id() != "" {
log.Debugf("utilityPfwCheckPresence: setting context from d.Id() %s", d.Id()) log.Debugf("utilityPfwCheckPresence: setting context from PFW ID %s", d.Id())
idParts := strings.SplitN(d.Id(), ":", 2) idParts := strings.SplitN(d.Id(), ":", 2)
compId, _ = strconv.Atoi(idParts[0]) compId, _ = strconv.Atoi(idParts[0])
vinsId, _ = strconv.Atoi(idParts[1]) vinsId, _ = strconv.Atoi(idParts[1])
@ -74,9 +90,9 @@ func utilityPfwCheckPresence(d *schema.ResourceData, m interface{}) (string, err
log.Debugf("utilityPfwCheckPresence: setting Compute ID from schema") log.Debugf("utilityPfwCheckPresence: setting Compute ID from schema")
compId = scId.(int) compId = scId.(int)
vinsId = svId.(int) vinsId = svId.(int)
log.Debugf("utilityPfwCheckPresence: extractted Compute ID %d, ViNS %d", compId, vinsId) log.Debugf("utilityPfwCheckPresence: extracted Compute ID %d, ViNS %d", compId, vinsId)
} else { } else {
return "", fmt.Errorf("Cannot get context to check PFW rules neither from d.Id() nor from schema") return "", fmt.Errorf("Cannot get context to check PFW rules neither from PFW ID nor from schema")
} }
} }
@ -145,18 +161,44 @@ func utilityPfwCheckPresence(d *schema.ResourceData, m interface{}) (string, err
return "", err return "", err
} }
log.Debugf("utilityPfwCheckPresence: successfully read %d port forward rules for Compute ID %d, ViNS ID %d", log.Debugf("utilityPfwCheckPresence: successfully read %d port forward rules for Compute ID %d",
len(pfwListResp.Rules), compId, pfwListResp.Header.VinsID) len(pfwListResp.Rules), compId)
if len(pfwListResp.Rules) == 0 {
// this compute technically can have rules, but no rules are currently defined
return "", nil
}
if pfwListResp.Header.VinsID != vinsId { // Now we can double check that the PFWs we've got do belong to the compute & ViNS specified in the
// PFW definition. Do so by reading compute details and comparing NatableVinsID value with the
// specified ViNS ID
//
// We may reuse urlValues here, as it already contains computeId field (see initialization above)
apiResp, err, _ = controller.decortAPICall("POST", ComputeGetAPI, urlValues)
if err != nil || apiResp == "" {
log.Errorf("utilityPfwCheckPresence: failed to get Compute ID %d details", compId)
return "", err
}
compFacts := ComputeGetResp{}
err = json.Unmarshal([]byte(rulesResp), &apiResp)
if err != nil {
log.Errorf("utilityPfwCheckPresence: failed to unmarshal compute details for ID %d: %s", compId, err)
return "", err
}
if compFacts.NatableVinsID <= 0 {
log.Errorf("utilityPfwCheckPresence: compute ID %d is not connected to a NAT-able ViNS", compId)
return "", fmt.Errorf("Compute ID %d is not connected to a NAT-able ViNS", compId)
}
if compFacts.NatableVinsID != vinsId {
log.Errorf("utilityPfwCheckPresence: ViNS ID mismatch for PFW rules on compute ID %d: actual %d, required %d", log.Errorf("utilityPfwCheckPresence: ViNS ID mismatch for PFW rules on compute ID %d: actual %d, required %d",
compId, pfwListResp.Header.VinsID, vinsId) compId, compFacts.NatableVinsID, vinsId)
return "", fmt.Errorf("ViNS ID mismatch for PFW rules on compute ID %d: actual %d, required %d", return "", fmt.Errorf("ViNS ID mismatch for PFW rules on compute ID %d: actual %d, required %d",
compId, pfwListResp.Header.VinsID, vinsId) compId, compFacts.NatableVinsID, vinsId)
} }
// reconstruct API response string for return // reconstruct API response string to return
pfwListResp.Header.ComputeID = compId pfwListResp.Header.ComputeID = compId
pfwListResp.Header.VinsID = compFacts.NatableVinsID
reencodedItem, err := json.Marshal(pfwListResp) reencodedItem, err := json.Marshal(pfwListResp)
if err != nil { if err != nil {
return "", err return "", err

Loading…
Cancel
Save