Can you edit vsi bandwith allocation via virtual.go:EditObject()? - go

I am using a modified version of this script: https://softlayer.github.io/go/edit_virtual_guest.go/
The script is the same except my objectTemplate looks like:
var objectTemplate datatypes.Virtual_Guest
objectTemplate.BandwidthAllocation = sl.Float(250)
The output after running is "Virtual Guest Server was successfully edited" but my vsi does not show updated bandwidth in the ui.
Is it possible to edit bandwidth using the EditObject call? Is it possible to edit the bandwidth using a different api call?

The “bandwidthAllocation” attribute that you are using does not work to edit the bandwidth of a virtual server, I suggest you to use SoftLayer_Product_Order::placeOrder to upgrade your bandwidth because the control portal use this method and service to do that.
There is not possible to edit bandwidth using the EditObject call.
This is a go example that you can use to upgrade your bandwidth:
/*
Upgrade bandwidth of a virtual server.
Build a SoftLayer_Container_Product_Order_Virtual_Guest object for a new virtual server order and
pass it to the SoftLayer_Product_Order API service to order it.
See below for more details.
Important manual pages:
http://sldn.softlayer.com/reference/services/SoftLayer_Product_Order/verifyOrder
http://sldn.softlayer.com/reference/services/SoftLayer_Product_Order/placeOrder
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Virtual_Guest
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Container_Product_Order
https://softlayer.github.io/reference/datatypes/SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade/
License: http://sldn.softlayer.com/article/License
Author: SoftLayer Technologies, Inc. <sldn#softlayer.com>
*/
package main
import (
"fmt"
"github.com/softlayer/softlayer-go/datatypes"
"github.com/softlayer/softlayer-go/services"
"github.com/softlayer/softlayer-go/session"
"github.com/softlayer/softlayer-go/sl"
"encoding/json"
)
func main() {
// SoftLayer API username and key
username := "set me"
apikey := "set me"
// Declare the id for the virtual server you wish to order.
vmId := 11111
// Build a skeleton SoftLayer_Virtual_Guest object.
virtualGuests := []datatypes.Virtual_Guest {
{ // id of SoftLayer_Virtual_Guest object
Id: sl.Int(vmId),
},
}
// Build a skeleton SoftLayer_Product_Item_Price objects. To get the list of valid
// prices for the package use the SoftLayer_Product_Package:getItems method
prices := []datatypes.Product_Item_Price {
{ Id: sl.Int(50231) }, // 1000 GB Bandwidth
}
properties := []datatypes.Container_Product_Order_Property{
{
Name: sl.String("NOTE_GENERAL"),
Value: sl.String("upgrade bandwidth"),
},
{
Name: sl.String("MAINTENANCE_WINDOW"),
Value: sl.String("2018-07-26T19:20:14.743Z"),
},
{
Name: sl.String("orderOrigin"),
Value: sl.String("control"),
},
}
// Build a Container_Product_Order object containing the order you wish to place.
orderTemplate := datatypes.Container_Product_Order{
ComplexType : sl.String("SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade"),
VirtualGuests : virtualGuests,
Prices : prices,
Properties: properties,
}
hardwareContainer := datatypes.Container_Product_Order_Hardware_Server{
Container_Product_Order: orderTemplate,
}
virtualGuestContainer := datatypes.Container_Product_Order_Virtual_Guest{
Container_Product_Order_Hardware_Server: hardwareContainer,
}
orderContainer := &datatypes.Container_Product_Order_Virtual_Guest_Upgrade{
Container_Product_Order_Virtual_Guest: virtualGuestContainer,
}
// Create a session
sess := session.New(username, apikey)
// Get SoftLayer_Product_Order service
service := services.GetProductOrderService(sess)
// Use verifyOrder() method to check for errors. Replace this with placeOrder() when
// you are ready to order.
receipt, err := service.VerifyOrder(orderContainer)
if err != nil {
fmt.Printf("\n Unable to place order:\n - %s\n", err)
return
}
// Following helps to print the result in json format.
jsonFormat, jsonErr := json.MarshalIndent(receipt, "", " ")
if jsonErr != nil {
fmt.Println(jsonErr)
return
}
fmt.Println(string(jsonFormat))
}
To get the item prices and their respective locations available you can use the following example:
/*
GetItemPrices
Retrieve a collection of SoftLayer_Product_Item_Prices that are valid for this package.
Important manual pages:
https://softlayer.github.io/reference/services/SoftLayer_Product_Package/getItemPrices/
License: http://sldn.softlayer.com/article/License
Author: SoftLayer Technologies, Inc. <sldn#softlayer.com>
*/
package main
import (
"fmt"
"github.com/softlayer/softlayer-go/services"
"github.com/softlayer/softlayer-go/session"
"encoding/json"
"terraform-provider-softlayer/softlayer"
)
func main() {
softlayer.Provider()
// SoftLayer API username and key
username := "set me"
apikey := "set me"
packageId := 46
mask := "id;locationGroupId;item[id,keyName,description];pricingLocationGroup[locations[id, name, longName]]"
// Create a session
sess := session.New(username, apikey)
service := services.GetProductPackageService(sess)
receipt, err := service.Id(packageId).Mask(mask).GetItemPrices()
if err != nil {
fmt.Printf("\n Unable to retrieve the item prices:\n - %s\n", err)
return
}
// Following helps to get the result in json format.
// Following helps to print the result in json format.
jsonFormat, jsonErr := json.MarshalIndent(receipt, "", " ")
if jsonErr != nil {
fmt.Println(jsonErr)
return
}
fmt.Println(string(jsonFormat))
}

Related

Running Azure SDK for Go return an error: MSI not available

I am trying to run Golang Azure SDK code to get a list of RGs in my subscriptions but I am getting the following error:
2022/01/22 20:25:58 MSI not available
exit status 1
import (
"context"
"fmt"
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2020-10-01/resources"
"github.com/Azure/go-autorest/autorest/azure/auth"
"github.com/Azure/go-autorest/autorest/to"
"log"
"os"
)
func main() {
authorize, err := auth.NewAuthorizerFromEnvironment()
if err != nil {
log.Fatal(err)
}
subscriptionID := os.Getenv("AZURE_SUB_ID")
//Read resource groups
resGrpClient := resources.NewGroupsClient(subscriptionID)
resGrpClient.Authorizer = authorize
//Read resources within the resource group
resClient := resources.NewClient(subscriptionID)
resClient.Authorizer = authorize
for resGrpPage, err := resGrpClient.List(context.Background(), "", nil); resGrpPage.NotDone(); err = resGrpPage.Next() {
if err != nil {
log.Fatal(err)
}
for _, resGrp := range resGrpPage.Values() {
fmt.Println("Resource Group Name: ", to.String(resGrp.Name))
resList, _ := resClient.ListByResourceGroup(context.Background(), to.String(resGrp.Name), "", "", nil)
for _, res := range resList.Values() {
fmt.Println("\t- Resource Name: ", to.String(res.Name), " | Resource Type: ", to.String(res.Type))
}
}
}
}
I am using Goland and trying to run the app in WSL Ubuntu
Solution is to use auth.NewAuthorizerFromCLI(), as auth.NewAuthorizerFromEnvironment does not use the Cli and MSI stands for managed system identity.
Please read this documentation Use environment-based authentication
You have a couple of options
and they need specific environments variables to be present.
In my case, I use Client credentials so I need to have these 3 envs present when I run my code.
AZURE_CLIENT_ID
AZURE_CLIENT_SECRET
AZURE_TENANT_ID

How can I debug my Golang API code to show me what is wrong?

I have this module that use Google Cloud API to retrieve a list of all running Virtual Machine instances for a particular project. I'm new to Go, and followed the intro tutorial to help me out. I'm still trying to debug my code but no luck.
The problem is I'm able to communicate to Google Cloud API and pass authentication but that is all I can get through
compute.go module:
compute.go is able to communicate to Google Cloud servers and pass authentication (I'm not getting an auth error)
// Copyright 2021 Google LLC
//
// 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
//
// https://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 compute
// [START compute_instances_list_all]
import (
"context"
"fmt"
"io"
compute "cloud.google.com/go/compute/apiv1"
"google.golang.org/api/iterator"
computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
"google.golang.org/protobuf/proto"
)
// listAllInstances prints all instances present in a project, grouped by their zone.
func ListAllInstances(w io.Writer, projectID string) error {
// projectID := "your_project_id"
ctx := context.Background()
instancesClient, err := compute.NewInstancesRESTClient(ctx)
// instancesClient, err := compute.NewInstancesRESTClient(ctx, option.WithCredentialsFile(`C:\path\to\jsonkey.json`))
if err != nil {
return fmt.Errorf("NewInstancesRESTClient: %v", err)
}
defer instancesClient.Close()
// Use the `MaxResults` parameter to limit the number of results that the API returns per response page.
req := &computepb.AggregatedListInstancesRequest{
Project: projectID,
MaxResults: proto.Uint32(6),
}
it := instancesClient.AggregatedList(ctx, req)
fmt.Fprintf(w, "Instances found:\n")
// Despite using the `MaxResults` parameter, you don't need to handle the pagination
// yourself. The returned iterator object handles pagination
// automatically, returning separated pages as you iterate over the results.
for {
pair, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
return err
}
instances := pair.Value.Instances
if len(instances) > 0 {
fmt.Fprintf(w, "%s\n", pair.Key)
for _, instance := range instances {
fmt.Fprintf(w, "- %s %s\n", instance.GetName(), instance.GetMachineType())
}
}
}
return nil
}
// [END compute_instances_list_all]
However the problem is when I run my main function that calls ListAllInstances, it returns a <nil>. Not allowing me to know what is wrong.
caller api.go module where I run go run .:
package main
import (
"fmt"
"example.com/compute"
"bytes"
)
func main() {
buf := new(bytes.Buffer)
// Get a message and print it.
respone := compute.ListAllInstances(buf, "project-unique-id")
fmt.Println(respone)
}
How else can I further debug this to figure out what is wrong with my code?
You're not printing buf. Your function returns an object of type error, which is nil (no error!), the actual output is written to buf.
Either print it out:
func main() {
buf := new(bytes.Buffer)
// Get a message and print it.
err := compute.ListAllInstances(buf, "project-unique-id")
if err != nil {
panic(err)
}
fmt.Println(buf.String()) // <======= Print buf contents!
}
Or just use os.Stdout:
func main() {
err := compute.ListAllInstances(os.Stdout, "project-unique-id")
if err != nil {
panic(err)
}
}
To answer your question about debugging, try using VSCode with the Go extension, in there you can run a debugger, set breakpoints and step through the code line-by-line, watching how variables change.
See also Debug Go programs in VS Code.

How to order a softlayer network gateway with ssh configured for Gateway and its member

How to order a softlayer network gateway with ssh configured for Gateway and its member
package main
import (
"fmt"
"github.com/softlayer/softlayer-go/datatypes"
"github.com/softlayer/softlayer-go/services"
"github.com/softlayer/softlayer-go/session"
"github.com/softlayer/softlayer-go/sl"
"encoding/json"
)
func main() {
// SoftLayer API username and key
username := "set me"
apikey := "set me"
// Build a Container_Product_Order_Virtual_Disk_Image object containing the order
// you wish to place
order := datatypes.Container_Product_Order{
ContainerIdentifier: sl.String(d.Get("hostname").(string)),
Quantity: sl.Int(1),
Hardware: []datatypes.Hardware{
{
Hostname: sl.String(d.Get("hostname").(string)),
Domain: sl.String(d.Get("domain").(string)),
},
},
Location: sl.String(strconv.Itoa(*dc.Id)),
PackageId: pkg.Id,
Prices: []datatypes.Product_Item_Price{
server,
os,
ram,
portSpeed,
priIpAddress,
remoteManagement,
vpnManagement,
monitoring,
notification,
response,
vulnerabilityScanner,
},
}
// Set SSH Key on main order
ssh_key_ids := members[0].Get("ssh_key_ids").([]interface{})
sshKeyP := make([]int, len(ssh_key_ids))
for i, ssh_key_id := range ssh_key_ids {
sshKeyP[i] = ssh_key_id.(int)
}
order.SshKeys = make([]datatypes.Container_Product_Order_SshKeys, len(members))
order.SshKeys[0] = datatypes.Container_Product_Order_SshKeys{
SshKeyIds: sshKeyP,
}
// Create a session
sess := session.New(username, apikey)
// Get SoftLayer_Product_Order service
service := services.GetProductOrderService(sess)
// Use verifyOrder() method to check for errors. Replace this with placeOrder() when
// you are ready to order.
receipt, err := service.VerifyOrder(&templateObject)
if err != nil {
fmt.Printf("\n Unable to place order:\n - %s\n", err)
return
}
// Following helps to print the result in json format.
jsonFormat, jsonErr := json.MarshalIndent(receipt, ""," ")
if jsonErr != nil {
fmt.Println(jsonErr)
return
}
fmt.Println(string(jsonFormat))
}
This is the script I am using to order, but it configures the ssh keys only for the gateway member but not the gateway. could you please help me on how to configure the ssh key for gateway and its member. It would be great if you could update the same script and share it.
SoftLayer Network Gateway is an object which consists of either one member (standalone) or 2 members (High Availability). When you accessing a gateway via ssh, it actually establishes ssh session with one of gateway member. So you can only configure ssh key for gateway members, not gateway itself.

How to add object mask to call GetNetworkVlans using golang

func getPrivateVlan(env string) (string, error) {
// 1. Create a session
sess := session.New(user, pass)
// 2. Get a service
accountService := services.GetAccountService(sess)
// 3. Invoke a method:
vlans, err := accountService.GetNetworkVlans()
vlan := vlans[0]
log.Println(*vlan.Name) //works
log.Println(*vlan.PrimaryRouter) //Doesn't work
}
The object returned is an array of vlans of type SoftLayer_Network_Vlan, https://sldn.softlayer.com/reference/datatypes/softlayer_network_vlan.
I am able to access the properties in column "Local Properties" (ie Name) but am unable to access the properties in column "Relational & Count Properties" (ie PrimaryRouter).
How can I add an object mask to my call in order to see these properties?
The reason is that in order to obtain relational data from an object in the API you must declare an object mask in your API call, as far as I can see, it is not declared in your code, it should be something like this:
func getPrivateVlan(env string) (string, error) {
// 1. Create a session
sess := session.New(user, pass)
// 2. Get a service
accountService := services.GetAccountService(sess)
//declare Mask
object_mask := "id;name;primaryRouter"
// 3. Invoke a method including the Object mask:
vlans, err := accountService.Mask(object_mask).GetNetworkVlans()
vlan := vlans[0]
log.Println(*vlan.Name) //works
log.Println(*vlan.PrimaryRouter) //
}
Try the following code for example:
package main
import (
"fmt"
"github.com/softlayer/softlayer-go/services"
"github.com/softlayer/softlayer-go/session"
"encoding/json"
)
func main() {
// SoftLayer API username and key
username := "set-me"
apikey := "set-me"
// Create a session
sess := session.New(username, apikey)
// Get SoftLayer_Account service
service := services.GetAccountService(sess)
// Object-Mask to get specific Vlan's information
mask := "id;name;primaryRouter"
// Call to getNetworkVlans in order to retrieve vlans according to filter.
result, err := service.Mask(mask).GetNetworkVlans()
if err != nil {
fmt.Printf("\n Unable to retrieve vlans:\n - %s\n", err)
return
}
// Following helps to print the result in json format.
jsonFormat, jsonErr := json.MarshalIndent(result,""," ")
if jsonErr != nil {
fmt.Println(jsonErr)
return
}
fmt.Println(string(jsonFormat))
}
For more information please see below:
https://sldn.softlayer.com/article/object-masks#Property_Set
source: Unable to get itemCategory info from call GetConfiguration when called from golang
F.Ojeda:
The default endpoint is REST but in your environment you are using xmlrpc, which is probably due to the existence of the ~ / .softlayer file and in this it is configured as an XMLRPC enpoint.
For more information you can see the following documentation: https://github.com/softlayer/softlayer-go
This issue happens for the XMLRPC enpoint and you can report it in the go GitHub. https://github.com/softlayer/softlayer-go/issues/
Try in your code with the REST endpoint, like this example:
endpoint := "https://api.softlayer.com/rest/v3"
// Create a session
sess := session.New(username, apikey, endpoint)

(Go) How to use toml files?

As title, I want to know how to use toml files from golang.
Before that, I show my toml examples. Is it right?
[datatitle]
enable = true
userids = [
"12345", "67890"
]
[datatitle.12345]
prop1 = 30
prop2 = 10
[datatitle.67890]
prop1 = 30
prop2 = 10
And then, I want to set these data as type of struct.
As a result I want to access child element as below.
datatitle["12345"].prop1
datatitle["67890"].prop2
Thanks in advance!
First get BurntSushi's toml parser:
go get github.com/BurntSushi/toml
BurntSushi parses toml and maps it to structs, which is what you want.
Then execute the following example and learn from it:
package main
import (
"github.com/BurntSushi/toml"
"log"
)
var tomlData = `title = "config"
[feature1]
enable = true
userids = [
"12345", "67890"
]
[feature2]
enable = false`
type feature1 struct {
Enable bool
Userids []string
}
type feature2 struct {
Enable bool
}
type tomlConfig struct {
Title string
F1 feature1 `toml:"feature1"`
F2 feature2 `toml:"feature2"`
}
func main() {
var conf tomlConfig
if _, err := toml.Decode(tomlData, &conf); err != nil {
log.Fatal(err)
}
log.Printf("title: %s", conf.Title)
log.Printf("Feature 1: %#v", conf.F1)
log.Printf("Feature 2: %#v", conf.F2)
}
Notice the tomlData and how it maps to the tomlConfig struct.
See more examples at https://github.com/BurntSushi/toml
A small update for the year 2019 - there is now newer alternative to BurntSushi/toml with a bit richer API to work with .toml files:
pelletier/go-toml (and documentation)
For example having config.toml file (or in memory):
[postgres]
user = "pelletier"
password = "mypassword"
apart from regular marshal and unmarshal of the entire thing into predefined structure (which you can see in the accepted answer) with pelletier/go-toml you can also query individual values like this:
config, err := toml.LoadFile("config.toml")
if err != nil {
fmt.Println("Error ", err.Error())
} else {
// retrieve data directly
directUser := config.Get("postgres.user").(string)
directPassword := config.Get("postgres.password").(string)
fmt.Println("User is", directUser, " and password is", directPassword)
// or using an intermediate object
configTree := config.Get("postgres").(*toml.Tree)
user := configTree.Get("user").(string)
password := configTree.Get("password").(string)
fmt.Println("User is", user, " and password is", password)
// show where elements are in the file
fmt.Printf("User position: %v\n", configTree.GetPosition("user"))
fmt.Printf("Password position: %v\n", configTree.GetPosition("password"))
// use a query to gather elements without walking the tree
q, _ := query.Compile("$..[user,password]")
results := q.Execute(config)
for ii, item := range results.Values() {
fmt.Println("Query result %d: %v", ii, item)
}
}
UPDATE
There is also spf13/viper that works with .toml config files (among other supported formats), but it might be a bit overkill in many cases.
UPDATE 2
Viper is not really an alternative (credits to #GoForth).
This issue was solved using recommended pkg BurntSushi/toml!!
I did as below and it's part of code.
[toml example]
[title]
enable = true
[title.clientinfo.12345]
distance = 30
some_id = 6
[Golang example]
type TitleClientInfo struct {
Distance int `toml:"distance"`
SomeId int `toml:"some_id"`
}
type Config struct {
Enable bool `toml:"enable"`
ClientInfo map[string]TitleClientInfo `toml:"clientinfo"`
}
var config Config
_, err := toml.Decode(string(d), &config)
And then, it can be used as I expected.
config.ClientInfo[12345].Distance
Thanks!
With solution Viper you can use a configuration file in JSON, TOML, YAML, HCL, INI and others properties formats.
Create file:
./config.toml
First import:
import (config "github.com/spf13/viper")
Initialize:
config.SetConfigName("config")
config.AddConfigPath(".")
err := config.ReadInConfig()
if err != nil {
log.Println("ERROR", err.Error())
}
And get the value:
config.GetString("datatitle.12345.prop1")
config.Get("datatitle.12345.prop1").(int32)
Doc.: https://github.com/spf13/viper
e.g.: https://repl.it/#DarlanD/Viper-Examples#main.go
I am using this [1] go-toml library.
It works great for my uses. I wrote this [2] go util to deal with containerd config.toml file using go-toml
[1]https://github.com/pelletier/go-toml
[2]https://github.com/prakashmirji/toml-configer
I am using spf13/viper
3rd packages
Status
Project
Starts
Forks
Alive
spf13/viper
Alive
BurntSushi/toml
usage of viper
I tried to use a table to put the code and the contents of the configuration file together, but obviously, the editing did not match the final result, so I put the image up in the hope that it would make it easier for you to compare
package main
import (
"github.com/spf13/viper"
"log"
"os"
)
func main() {
check := func(err error) {
if err != nil {
panic(err)
}
}
myConfigPath := "test_config.toml"
fh, err := os.OpenFile(myConfigPath, os.O_RDWR, 0666)
check(err)
viper.SetConfigType("toml") // do not ignore
err = viper.ReadConfig(fh)
check(err)
// Read
log.Printf("%#v", viper.GetString("title")) // "my config"
log.Printf("%#v", viper.GetString("DataTitle.12345.prop1")) // "30"
log.Printf("%#v", viper.GetString("dataTitle.12345.prop1")) // "30" // case-insensitive
log.Printf("%#v", viper.GetInt("DataTitle.12345.prop1")) // 30
log.Printf("%#v", viper.GetIntSlice("feature1.userids")) // []int{456, 789}
// Write
viper.Set("database", "newuser")
viper.Set("owner.name", "Carson")
viper.Set("feature1.userids", []int{111, 222}) // overwrite
err = viper.WriteConfigAs(myConfigPath)
check(err)
}
title = "my config"
[datatitle]
[datatitle.12345]
prop1 = 30
[feature1]
userids = [456,789]
database = "newuser" # New
title = "my config"
[datatitle]
[datatitle.12345]
prop1 = 30
[feature1]
userids = [111,222] # Update
[owner] # New
name = "Carson"

Resources