Note: See the Parameters
struct to know what data you can set at order time.
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/softlayer/softlayer-go/datatypes"
"github.com/softlayer/softlayer-go/filter"
"github.com/softlayer/softlayer-go/services"
"github.com/softlayer/softlayer-go/session"
"github.com/softlayer/softlayer-go/sl"
)
// Create the session and services
var sess = session.New()
var packageService = services.GetProductPackageService(sess)
var orderService = services.GetProductOrderService(sess)
// Parameters will help us to reduce the number of argumments in a function
// and not all of them are required. e.g. hostID, reservedCapacityID,sshKeys, etc.
type Parameters struct {
hostname string
domain string
pkgName string
flavor string
hourly bool
hostID int // To order in an specific dedicated host
reservedCapacityID int // To order in a reerved capacity
location string
items []string
publicVlanID int
privateVlanID int
sshKeys []int
postScripts []string
}
func main() {
// KeyNames of the items
items := []string{
"1_GBPS_PUBLIC_PRIVATE_NETWORK_UPLINKS",
"BANDWIDTH_0_GB_2", "1_IP_ADDRESS",
"OS_UBUNTU_16_04_LTS_XENIAL_XERUS_MINIMAL_64_BIT_FOR_VSI",
"REBOOT_REMOTE_CONSOLE",
"MONITORING_HOST_PING", "NOTIFICATION_EMAIL_AND_TICKET", "AUTOMATED_NOTIFICATION",
"UNLIMITED_SSL_VPN_USERS_1_PPTP_VPN_USER_PER_ACCOUNT",
}
parameters := Parameters{
hostname: "myhostname",
domain: "domain.com",
publicVlanID: 2068353,
privateVlanID: 2068355,
// CLOUD_SERVER, SUSPEND_CLOUD_SERVER, PUBLIC_CLOUD_SERVER or TRANSIENT_CLOUD_SERVER
pkgName: "SUSPEND_CLOUD_SERVER",
flavor: "M1_1X8X25", // Remove this if you want to order a CLOUD_SERVER
location: "DALLAS13",
hourly: true, // Suspended and transient vsis can only be hourly
items: items,
sshKeys: []int{1253845, 1312903},
postScripts: []string{"https://xx.xx.xx.xx/folder/file.sh"},
}
OrderVirtualServer(parameters)
}
// OrderVirtualServer place/verify the order
func OrderVirtualServer(args Parameters) {
// Get the packageId and prices
packageID := GetPackageID(args.pkgName)
prices := GetPrices(*packageID, args.items)
// Build the Virtual_Guest array object
virtualGuests := BuildArrayVirtualGuests(args)
// Build the Container_Product_Order with the basic required data
containerOrder := datatypes.Container_Product_Order{
PackageId: packageID,
Location: sl.String(args.location),
VirtualGuests: virtualGuests,
Prices: prices,
UseHourlyPricing: sl.Bool(args.hourly),
}
// Add presetId to the Container_Product_Order if a flavor exists
if args.flavor != "" {
containerOrder.PresetId = GetPresetID(*packageID, args.flavor)
}
// Add sshKeys if Parameters struct has this value set
if len(args.sshKeys) > 0 {
containerOrder.SshKeys = []datatypes.Container_Product_Order_SshKeys{
{SshKeyIds: args.sshKeys},
}
}
// Add post provision scripts if Parameters struct has this value set
if len(args.postScripts) > 0 {
containerOrder.ProvisionScripts = args.postScripts
}
// Build the order template that will be used to order the virtual server
orderTemplate := datatypes.Container_Product_Order_Virtual_Guest{
Container_Product_Order_Hardware_Server: datatypes.Container_Product_Order_Hardware_Server{
Container_Product_Order: containerOrder,
},
}
// Add the hostId or reserved capacity if they were added in the parameters
if args.hostID > 0 {
orderTemplate.HostId = sl.Int(args.hostID)
}
if args.reservedCapacityID > 0 {
orderTemplate.ReservedCapacityId = sl.Int(args.reservedCapacityID)
}
// Use verifyOrder() method to check for errors. Replace this with placeOrder() when
// you are ready to order.
receipt, err := orderService.VerifyOrder(&orderTemplate)
if err != nil {
fmt.Printf("Unable to verify/place the order: %s", err)
}
// pretty print
jsonFormat, jsonErr := json.MarshalIndent(receipt, "", " ")
if jsonErr != nil {
fmt.Println(jsonErr)
return
}
fmt.Println(string(jsonFormat))
}
// GetPackageID returns the package id
func GetPackageID(keyName string) *int {
objFilter := filter.Path("keyName").Eq(keyName).Build()
packages, err := packageService.Mask("mask[id]").Filter(objFilter).GetAllObjects()
if err != nil {
fmt.Printf("Package %s doesn't exists\n", keyName)
os.Exit(1)
}
return packages[0].Id
}
// GetPresetID returns the presetID of a flavor
func GetPresetID(packageID int, flavor string) *int {
objFilter := filter.Path("keyName").Eq(flavor).Build()
presets, err := packageService.Filter(objFilter).Id(packageID).GetActivePresets()
if err != nil {
fmt.Printf("Flavor %s doesn't exists\n", flavor)
os.Exit(1)
}
return presets[0].Id
}
// GetPrices returns the list of prices
func GetPrices(packageID int, itemKeyNames []string) []datatypes.Product_Item_Price {
objMask := "mask[id,itemCategory,keyName,prices[categories]]"
items, err := packageService.Mask(objMask).Id(packageID).GetItems()
if err != nil {
fmt.Printf("Unable to retrieve items: %s\n", err)
os.Exit(1)
}
prices := make([]datatypes.Product_Item_Price, len(itemKeyNames))
for idx, itemKeyName := range itemKeyNames {
prices[idx].Id, err = GetPriceIDIfMatch(itemKeyName, items)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
return prices
}
// GetPriceIDIfMatch returns a priceID or error if keyName doesnt exists
func GetPriceIDIfMatch(keyName string, items []datatypes.Product_Item) (priceID *int, err error) {
var matchingItem datatypes.Product_Item
// find the item keyname
for _, item := range items {
if keyName == *item.KeyName {
matchingItem = item
break
}
}
// returns error if keyName doesn't exists in the items list
if matchingItem.KeyName == nil {
return nil, fmt.Errorf("The item %s doesn't exists in the package", keyName)
}
// find the standard priceID
for _, price := range matchingItem.Prices {
if price.LocationGroupId == nil {
priceID = price.Id
break
}
}
return
}
// BuildArrayVirtualGuests builds the esqueleton of Virtual_Guest array
func BuildArrayVirtualGuests(args Parameters) []datatypes.Virtual_Guest {
virtualGuests := []datatypes.Virtual_Guest{
{
Hostname: sl.String(args.hostname),
Domain: sl.String(args.domain),
},
}
if args.privateVlanID > 0 {
virtualGuests[0].PrimaryBackendNetworkComponent = &datatypes.Virtual_Guest_Network_Component{
NetworkVlan: &datatypes.Network_Vlan{
Id: sl.Int(args.privateVlanID),
},
}
}
if args.publicVlanID > 0 {
virtualGuests[0].PrimaryNetworkComponent = &datatypes.Virtual_Guest_Network_Component{
NetworkVlan: &datatypes.Network_Vlan{
Id: sl.Int(args.publicVlanID),
},
}
}
return virtualGuests
}