November 23, 2017


delete_firewall_rule_from_vsi.go

delete_firewall_rule_from_vsi.go
/*
Delete a firewall rule from a  VSI.

Important manual pages:
http://sldn.softlayer.com/reference/services/SoftLayer_Virtual_Guest/findByIpAddress
http://sldn.softlayer.com/reference/services/SoftLayer_Virtual_Guest/getFirewallServiceComponent
http://sldn.softlayer.com/reference/services/SoftLayer_Network_Firewall_Update_Request/createObject

License: http://sldn.softlayer.com/article/License
Author: SoftLayer Technologies, Inc. <sldn@softlayer.com>
*/
package main

import (
	"fmt"
	"encoding/json"
	"github.com/softlayer/softlayer-go/session"
	"github.com/softlayer/softlayer-go/services"
	"github.com/softlayer/softlayer-go/datatypes"
	"github.com/softlayer/softlayer-go/sl"
	"reflect"
)

func main() {
	// SoftLayer API username and key
	username := "set me"
	apikey   := "set me"

	// The id of Virtual server you wish to retrieve it firewall rules
	vsiId := 33051333

	/*
	Firewall rule information you want to delete. If you want to delete rules which don't have
	attributes like destinationPortRangeStart and DestinationPortRangeEnd, case for icmp
	protocol, just put 'nil' next to the attribute
	*/
	oldRule := datatypes.Network_Component_Firewall_Rule {
		Action                    : sl.String("permit"),
		Protocol                  : sl.String("icmp"),
		Version 	          : sl.Int(4),
		SourceIpAddress           : sl.String("10.8.0.0"),
		DestinationIpAddress      : sl.String("any on server"),
		SourceIpCidr              : sl.Int(32),
		DestinationPortRangeStart : nil,
		DestinationPortRangeEnd   : nil,
	}

	// Create SoftLayer API session
	sess := session.New(username, apikey)

	// Get SoftLayer_Virtual_Guest and SoftLayer_Network_Component_Firewall services
	guestService := services.GetVirtualGuestService(sess)
	firewallService := services.GetNetworkComponentFirewallService(sess)
	firewallUpdateService := services.GetNetworkFirewallUpdateRequestService(sess)

	// 1. Get the Firewall Service Component
	firewall, err := guestService.Id(vsiId).GetFirewallServiceComponent()
	if err != nil {
		fmt.Printf("\n Unable to get firewall component:\n - %s\n", err)
		return
	}

	// The following mask is to get specific data of firewall rules, retrieved data will be
	// compared in order to retrieve the rule we want to update.
	mask := "orderValue;action;protocol;sourceIpAddress;sourceIpCidr;version;" +
		"destinationIpAddress;destinationPortRangeStart;destinationPortRangeEnd"

	// 2. Retrieve all current firewall rules
	currentRules, err := firewallService.Id(*firewall.Id).Mask(mask).GetRules()
	if err != nil {
		fmt.Printf("\n Unable to get firewall rules:\n - %s\n", err)
		return
	}

	// This variable will be used to save current rules except the rule you wan to delete,
	// this into an array object SoftLayer_Network_Firewall_Update_Request_Rule
	firewallRules := []datatypes.Network_Firewall_Update_Request_Rule {}

	// 4. Save all current rules except that one which have same values of 'oldRule'.
	for _, rule := range currentRules {
		ruleOrder := *rule.OrderValue
		rule.OrderValue = nil
		if !reflect.DeepEqual(rule, oldRule) {
			currentRule := convertToSingleFirewallRule(rule).(datatypes.Network_Firewall_Update_Request_Rule)
			currentRule.OrderValue = sl.Int(ruleOrder)
			firewallRules = append(firewallRules, currentRule)
		}
	}

	// 5. Build the Network_Firewall_Update_Request_Rule object with the firewall rules.
	template := datatypes.Network_Firewall_Update_Request {
		NetworkComponentFirewallId : sl.Int(*firewall.Id),
		Rules                      : firewallRules,
	}

	// 6. Call to createObject() method in order to set firewall rules with all changes.
	updateRequest, err := firewallUpdateService.CreateObject(&template)
	if err != nil {
		fmt.Printf("\n Unable to replace/update all firewall rules:\n - %s\n", err)
		return
	}

	// Following helps to print the result in json format.
	jsonFormat, jsonErr := json.MarshalIndent(updateRequest,"","     ")
	if jsonErr != nil {
		fmt.Println(jsonErr)
		return
	}
	fmt.Println(string(jsonFormat))
}

/*
Following method converts an object type SoftLayer_Network_Component_Firewall_Rule to
SoftLayer_Network_Firewall_Update_Request_Rule
*/
func convertToSingleFirewallRule(object interface{}) interface{} {

	var result datatypes.Network_Firewall_Update_Request_Rule

	// Get the encoded JSON of object
	encoded, err := json.Marshal(object)
	if err != nil {
		fmt.Println(err)
	}

	// Inverse the encoded JSON and return an Network_Firewall_Update_Request_Rule
	if err := json.Unmarshal(encoded, &result); err != nil {
		fmt.Printf("%s\n", err)
	}

	return result
}