Overview
The CloudTower SDK in the Golang environment is applicable to golang 1.16 or above.
Installation
go get github.com/smartxworks/cloudtower-go-sdk
Use
The sample uses two tool libraries: pointy and go-funk.
Pointyis used to quickly create a pointer of a primitive type, andgo-funkprovides some tool methods, such as Map, Filter, and Reduce.
Create Instance
Create ApiClient Instance
import (
    apiclient "github.com/smartxworks/cloudtower-go-sdk/client"
    httptransport "github.com/go-openapi/runtime/client"
    "github.com/go-openapi/strfmt"
)
transport := httptransport.New("192.168.36.133", "/v2/api", []string{"http"})
client := apiclient.New(transport, strfmt.Default)
if https connection is required,cert should be installed,or skip verify cert
import (
apiclient "github.com/smartxworks/cloudtower-go-sdk/v2/client"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
tlsClient, err := httptransport.TLSClient(httptransport.TLSClientOptions{
InsecureSkipVerify: true,
})
if err != nil {
fmt.Print(err)
return
}
transport := httptransport.NewWithClient("192.168.29.157", "/v2/api", []string{"https"}, tlsClient)
client := apiclient.New(transport, strfmt.Default)
Send Request
Import Corresponding client Package
Import or create the
clientpackage corresponding to a specific operation.
import (
    vm "github.com/smartxworks/cloudtower-go-sdk/client/vm"
)
Verify Authentication
import (
  User "github.com/smartxworks/cloudtower-go-sdk/client/user"
)
loginParams := User.NewLoginParams()
loginParams.RequestBody = &models.LoginInput{
    Username: pointy.String("username"),
    Password: pointy.String("password"),
    Source:   models.NewUserSource(models.UserSourceLOCAL),
}
logRes, err := client.User.Login(loginParams)
if err != nil {
    return err
}
transport.DefaultAuthentication = httptransport.APIKeyAuth("Authorization", "header", *logRes.Payload.Data.Token)
Obtain Resources
getVmParams := vm.NewGetVmsParams();
getVmParams.RequestBody = &models.GetVmsRequestBody{
    Where: &models.VMWhereInput{
        ID: pointy.String("vm_id"),
    },
}
vmsRes, err := client.VM.GetVms(getVmParams)
if err != nil {
    return err
}
vms := vmsRes.Payload
Update Resources
Updating resources will have the asynchronous task. Resources will be updated when the asynchronous task is done.
target_vm := vmsRes.Payload[0]
vmStartParams := vm.NewStartVMParams()
vmStartParams.RequestBody = &models.VMStartParams{
    Where: &models.VMWhereInput{
        ID: target_vm.ID,
    },
}
startRes, err := client.VM.StartVM(vmStartParams)
if err != nil {
    return err
}
You can use the provided tool
WaitTaskto synchronously wait for the asynchronous task to end. If the task fails or times out, an error will be returned. The polling interval is 5 seconds, and the timeout period is 300 seconds.
- Tool Parameter Description
Parameter Type Must Have Description client *client.Cloudtower Yes Check the clientinstance.id string Yes The ID of the task you want to check. 
task := *startRes.Payload[0].TaskID
err = utils.WaitTask(client, task)
if err != nil {
    return err
}
In the case of multiple tasks, multiple task ids can be accepted via
WaitTasks. The rest is the same asWaitTask.
- Tool Parameter Description
Parameter Type Must Have Description client *client.Cloudtower Yes Check the clientinstance.ids []string Yes The ID list of the task you want to check. 
tasks := funk.Map(startRes.Payload, func(tvm *models.WithTaskVM) string {
    return *tvm.TaskID
}).([]string)
err = utils.WaitTasks(client, tasks)
if err != nil {
    return err
}
Others
Set Language of Returned Information
You can set the
ContentLanguageitem in the request params to set the language of the return value. The optional value is["en-US", "zh-CN"], and the default value isen-US. Languages not in the range of optional values will return an HTTP 400 error.
getTaskDefaultParams := task.NewGetTasksParams()
getTaskDefaultParams.RequestBody = &models.GetTasksRequestBody{
    First: pointy.Int32(10),
}
taskDefaultRes, err := client.Task.GetTasks(getTaskDefaultParams)
getTaskZhParams := task.NewGetTasksParams()
getTaskZhParams.RequestBody = &models.GetTasksRequestBody{
    First: pointy.Int32(10),
}
getTaskZhParams.ContentLanguage = pointy.String("zh-CN")
taskZhRes, err := client.Task.GetTasks(getTaskZhParams)
Scenario Examples
Virtual Machine Backup
package main
import (
    "fmt"
    apiclient "github.com/smartxworks/cloudtower-go-sdk/client"
    "github.com/smartxworks/cloudtower-go-sdk/client/iscsi_lun_snapshot"
    "github.com/smartxworks/cloudtower-go-sdk/client/user"
    "github.com/smartxworks/cloudtower-go-sdk/client/vm"
    "github.com/smartxworks/cloudtower-go-sdk/client/vm_snapshot"
    "github.com/smartxworks/cloudtower-go-sdk/models"
    "github.com/smartxworks/cloudtower-go-sdk/utils"
    "github.com/openlyinc/pointy"
    "github.com/thoas/go-funk"
    httptransport "github.com/go-openapi/runtime/client"
    "github.com/go-openapi/strfmt"
)
func create_vm_snapshot(
  client *apiclient.Cloudtower,
    targetVmName string,
    targetSnapshotName string,
    consistentType models.ConsistentType) (*models.VMSnapshot, []*models.IscsiLunSnapshot, error) {
    getVmParams := vm.NewGetVmsParams()
    getVmParams.RequestBody = &models.GetVmsRequestBody{
        Where: &models.VMWhereInput{
            Name: &targetVmName,
        },
        First: pointy.Int32(1),
    }
    getVmRes, err := client.VM.GetVms(getVmParams)
    if err != nil {
        return nil, nil, err
    }
    targetVm := getVmRes.Payload[0]
    vmToolStatus := *targetVm.VMToolsStatus
    if vmToolStatus != models.VMToolsStatusRUNNING && consistentType == models.ConsistentTypeFILESYSTEMCONSISTENT {
        consistentType = models.ConsistentTypeCRASHCONSISTENT
    }
    createSnapshotParams := vm_snapshot.NewCreateVMSnapshotParams()
    createSnapshotParams.RequestBody = &models.VMSnapshotCreationParams{
        Data: []*models.VMSnapshotCreationParamsDataItems0{
            {
                VMID:           targetVm.ID,
                Name:           &targetSnapshotName,
                ConsistentType: consistentType.Pointer(),
            },
        },
    }
    createRes, err := client.VMSnapshot.CreateVMSnapshot(createSnapshotParams)
    if err != nil {
        return nil, nil, err
    }
    withTaskSnapshot := createRes.Payload[0]
    err = utils.WaitTask(client, withTaskSnapshot.TaskID)
    if err != nil {
        return nil, nil, err
    }
    getSnapshotParams := vm_snapshot.NewGetVMSnapshotsParams()
    getSnapshotParams.RequestBody = &models.GetVMSnapshotsRequestBody{
        Where: &models.VMSnapshotWhereInput{
            ID: withTaskSnapshot.Data.ID,
        },
    }
    getSnapshotRes, err := client.VMSnapshot.GetVMSnapshots(getSnapshotParams)
    if err != nil {
        return nil, nil, err
    }
    createdSnapshot := getSnapshotRes.Payload[0]
    lunSnapshotIds := funk.Map(funk.Filter(createdSnapshot.VMDisks, func(disk *models.NestedFrozenDisks) bool {
        return *disk.Type == models.VMDiskTypeDISK
    }), func(disk *models.NestedFrozenDisks) string {
        return *disk.SnapshotLocalID
    }).([]string)
    getLunSnapshotParams := iscsi_lun_snapshot.NewGetIscsiLunSnapshotsParams()
    getLunSnapshotParams.RequestBody = &models.GetIscsiLunSnapshotsRequestBody{
        Where: &models.IscsiLunSnapshotWhereInput{
            NameIn: lunSnapshotIds,
        },
    }
    getLunSnapshotRes, err := client.IscsiLunSnapshot.GetIscsiLunSnapshots(getLunSnapshotParams)
    if err != nil {
        return nil, nil, err
    }
    return createdSnapshot, getLunSnapshotRes.Payload, nil
}
Build Dashboard
Define Tool Library
import (
    "fmt"
    apiclient "github.com/smartxworks/cloudtower-go-sdk/client"
    "github.com/smartxworks/cloudtower-go-sdk/client/alert"
    "github.com/smartxworks/cloudtower-go-sdk/client/cluster"
    "github.com/smartxworks/cloudtower-go-sdk/client/disk"
    "github.com/smartxworks/cloudtower-go-sdk/client/host"
    "github.com/smartxworks/cloudtower-go-sdk/client/user"
    "github.com/smartxworks/cloudtower-go-sdk/models"
    "github.com/openlyinc/pointy"
    "github.com/thoas/go-funk"
    httptransport "github.com/go-openapi/runtime/client"
    "github.com/go-openapi/strfmt"
)
var ByteUnits []string = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB"}
var HzUnits []string = []string{"Hz", "KHz", "MHz", "GHz", "THz"}
func formatUnit(base float64, units []string, step int32) string {
    length := len(units)
    if length == 0 {
        panic("No unit provided")
    }
    if base <= 0 {
        return fmt.Sprintf("0%s", units[0])
    }
    for i, unit := range units {
        if base < float64(step) || i == length-1 {
            return fmt.Sprintf("%0.2f%s", base, unit)
        }
        base = base / float64(step)
    }
    return fmt.Sprintf("%0.2f%s", base, units[length-1])
}
Build Alert Information
type AlertInfo struct {
    Critical []*models.Alert
    Notice   []*models.Alert
    Info     []*models.Alert
}
func NewAlertInfo(critial []*models.Alert, notice []*models.Alert, info []*models.Alert) *AlertInfo {
    return &AlertInfo{
        Critical: critial,
        Notice:   notice,
        Info:     info,
    }
}
func buildAlertInfo(client *apiclient.Cloudtower, clusterIds []string) (*AlertInfo, error) {
    getAlertParams := alert.NewGetAlertsParams()
    if len(clusterIds) == 0 {
        getAlertParams.RequestBody = &models.GetAlertsRequestBody{
            Where: &models.AlertWhereInput{
                Ended: pointy.Bool(false),
            },
        }
    } else {
        getAlertParams.RequestBody = &models.GetAlertsRequestBody{
            Where: &models.AlertWhereInput{
                Ended: pointy.Bool(false),
                Cluster: &models.ClusterWhereInput{
                    IDIn: clusterIds,
                },
            },
        }
    }
    res, err := client.Alert.GetAlerts(getAlertParams)
    if err != nil {
        return nil, err
    }
    var critial []*models.Alert = []*models.Alert{}
    var notice []*models.Alert = []*models.Alert{}
    var info []*models.Alert = []*models.Alert{}
    for _, alert := range res.Payload {
        switch *alert.Severity {
        case "CRITICAL":
            critial = append(critial, alert)
        case "NOTICE":
            notice = append(notice, alert)
        case "INFO":
            info = append(info, alert)
        }
    }
    return NewAlertInfo(critial, notice, info), nil
}
Build Hard Disk Information
Here is an example of a mechanical hard drive.
type DiskInfo struct {
    Healthy int32
    Warning int32
    Error   int32
    Total   int32
}
func NewDiskInfo() *DiskInfo {
    return &DiskInfo{
        Healthy: 0,
        Warning: 0,
        Error:   0,
        Total:   0,
    }
}
func buildHddInfo(client *apiclient.Cloudtower, clusterIds []string) (*DiskInfo, error) {
    getDiskParams := disk.NewGetDisksParams()
    if len(clusterIds) == 0 {
        getDiskParams.RequestBody = &models.GetDisksRequestBody{}
    } else {
        getDiskParams.RequestBody = &models.GetDisksRequestBody{
            Where: &models.DiskWhereInput{
                Host: &models.HostWhereInput{
                    Cluster: &models.ClusterWhereInput{
                        IDIn: clusterIds,
                    },
                },
            },
        }
    }
    res, err := client.Disk.GetDisks(getDiskParams)
    if err != nil {
        return nil, err
    }
    hddInfo := NewDiskInfo()
    for _, disk := range res.Payload {
        if *disk.Type == models.DiskTypeHDD {
            if funk.Contains(
                []models.DiskHealthStatus{
                    models.DiskHealthStatusHEALTHY,
                    models.DiskHealthStatusSUBHEALTHY,
                    models.DiskHealthStatusSMARTFAILED,
                },
                *disk.HealthStatus,
            ) {
                hddInfo.Error++
            } else if funk.Contains(
                []models.DiskUsageStatus{
                    models.DiskUsageStatusUNMOUNTED,
                    models.DiskUsageStatusPARTIALMOUNTED,
                },
                *disk.UsageStatus,
            ) {
                hddInfo.Warning++
            } else {
                hddInfo.Healthy++
            }
            hddInfo.Total++
        }
    }
    return hddInfo, nil
}
Build Performance Metrics
Get the number of CPU cores, total CPU frequency, CPU usage, total memory, memory usage, total storage resources, used storage resources, invalid storage resources, and available storage resources of the specified cluster.
type CpuInfo struct {
    TotalCore uint32
    TotalInHz uint64
    Total     string
    UsedInHz  uint64
    Used      string
    Usage     string
}
func NewCpuInfo() *CpuInfo {
    return &CpuInfo{
        TotalCore: 0,
        TotalInHz: 0,
        UsedInHz:  0,
    }
}
func (info *CpuInfo) compute() *CpuInfo {
    info.Total = formatUnit(float64(info.TotalInHz), HzUnits, 1000)
    info.Used = formatUnit(float64(info.UsedInHz), HzUnits, 1000)
    info.Usage = fmt.Sprintf("%0.2f%%", float64(info.UsedInHz)/float64(info.TotalInHz))
    return info
}
type MemoryInfo struct {
    TotalInByte uint64
    Total       string
    UsedInByte  uint64
    Used        string
    Usage       string
}
func NewMemoryInfo() *MemoryInfo {
    return &MemoryInfo{
        TotalInByte: 0,
        UsedInByte:  0,
    }
}
func (info *MemoryInfo) compute() *MemoryInfo {
    info.Total = formatUnit(float64(info.TotalInByte), ByteUnits, 1024)
    info.Used = formatUnit(float64(info.UsedInByte), ByteUnits, 1024)
    info.Usage = fmt.Sprintf("%0.2f%%", float64(info.UsedInByte)/float64(info.TotalInByte))
    return info
}
type StorageInfo struct {
    TotalInByte     uint64
    Total           string
    UsedInByte      uint64
    Used            string
    InvalidInByte   uint64
    Invalid         string
    AvailableInByte uint64
    Available       string
}
func NewStorageInfo() *StorageInfo {
    return &StorageInfo{
        TotalInByte:     0,
        UsedInByte:      0,
        InvalidInByte:   0,
        AvailableInByte: 0,
    }
}
func (info *StorageInfo) compute() *StorageInfo {
    info.AvailableInByte = info.TotalInByte - info.UsedInByte - info.InvalidInByte
    info.Total = formatUnit(float64(info.TotalInByte), ByteUnits, 1024)
    info.Used = formatUnit(float64(info.UsedInByte), ByteUnits, 1024)
    info.Invalid = formatUnit(float64(info.InvalidInByte), ByteUnits, 1024)
    info.Available = formatUnit(float64(info.AvailableInByte), ByteUnits, 1024)
    return info
}
type MetricInfo struct {
    Storage *StorageInfo
    Memory  *MemoryInfo
    Cpu     *CpuInfo
}
func buildMetricsInfo(client *apiclient.Cloudtower, clusters []*models.Cluster, clusterIds []string) (*MetricInfo, error) {
    memory := NewMemoryInfo()
    storage := NewStorageInfo()
    cpu := NewCpuInfo()
    getHostParams := host.NewGetHostsParams()
    if len(clusterIds) == 0 {
        getHostParams.RequestBody = &models.GetHostsRequestBody{}
    } else {
        getHostParams.RequestBody = &models.GetHostsRequestBody{
            Where: &models.HostWhereInput{
                Cluster: &models.ClusterWhereInput{
                    IDIn: clusterIds,
                },
            },
        }
    }
    hosts, err := client.Host.GetHosts(getHostParams)
    if err != nil {
        return nil, err
    }
    clusterIdMap := make(map[string]*models.Cluster)
    for _, cluster := range clusters {
        if _, ok := clusterIdMap[*cluster.ID]; !ok {
            clusterIdMap[*cluster.ID] = cluster
        }
        if *cluster.Type == models.ClusterTypeSMTXOS {
            cpu.TotalCore += uint32(*cluster.TotalCPUCores)
            cpu.TotalInHz += uint64(*cluster.TotalCPUHz)
            cpu.UsedInHz += uint64(*cluster.UsedCPUHz)
            if cluster.Hypervisor != nil && *cluster.Hypervisor == models.HypervisorVMWARE {
                memory.TotalInByte += uint64(*cluster.TotalMemoryBytes)
                memory.UsedInByte += uint64(*cluster.UsedMemoryBytes)
            }
        }
        storage.TotalInByte += uint64(*cluster.TotalDataCapacity)
        storage.UsedInByte += uint64(*cluster.UsedDataSpace)
        storage.InvalidInByte += uint64(*cluster.FailureDataSpace)
    }
    for _, host := range hosts.Payload {
        cluster, ok := clusterIdMap[*host.Cluster.ID]
        if ok {
            if *cluster.Hypervisor == models.HypervisorELF {
                memory.TotalInByte += uint64(*host.TotalMemoryBytes)
                memory.UsedInByte += uint64(*host.UsedMemoryBytes)
            }
        }
    }
    storage.compute()
    cpu.compute()
    memory.compute()
    return &MetricInfo{
        Memory:  memory,
        Cpu:     cpu,
        Storage: storage,
    }, nil
}
Build Dashboard
type DashboardInfo struct {
    Metric *MetricInfo
    Hdd    *DiskInfo
    Alert  *AlertInfo
}
func BuildDashboard(client *apiclient.Cloudtower, clusterIds []string) (*DashboardInfo, error) {
    getClusterParams := cluster.NewGetClustersParams()
    if len(clusterIds) == 0 {
        getClusterParams.RequestBody = &models.GetClustersRequestBody{}
    } else {
        getClusterParams.RequestBody = &models.GetClustersRequestBody{
            Where: &models.ClusterWhereInput{
                IDIn: clusterIds,
            },
        }
    }
    res, err := client.Cluster.GetClusters(getClusterParams)
    if err != nil {
        return nil, err
    }
    metrics, err := buildMetricsInfo(client, res.Payload, clusterIds)
    if err != nil {
        return nil, err
    }
    hdd, err := buildHddInfo(client, clusterIds)
    if err != nil {
        return nil, err
    }
    alert, err := buildAlertInfo(client, clusterIds)
    if err != nil {
        return nil, err
    }
    return &DashboardInfo{
        Metric: metrics,
        Hdd:    hdd,
        Alert:  alert,
    }, nil
}