Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

mrxinu/gosolar

Repository files navigation

gosolar

Go Reference Go Report Card CI codecov

GoSolar is a modern, production-ready Go client library for SolarWinds Information Service (SWIS). It provides a comprehensive wrapper around SWIS REST calls with context support, structured error handling, and strong typing while maintaining full backward compatibility.

Features

πŸš€ Modern Go Practices

  • Context Support - All operations support cancellation and timeouts
  • Structured Errors - Typed error system with proper error classification
  • Configuration-Based - Modern config pattern with validation and defaults
  • Strong Typing - Predefined structures for common SolarWinds entities
  • Retry Logic - Smart retry mechanism for network failures
  • Go Modules - Proper dependency management

πŸ”’ Production Ready

  • Comprehensive Testing - 100% test coverage with HTTP mocking
  • Security Best Practices - Environment-based configuration, credential validation
  • Connection Management - Optimized connection pooling and timeout handling
  • Structured Logging - Built-in logging with configurable levels

πŸ”„ Backward Compatible

  • Zero Breaking Changes - All existing code continues to work
  • Legacy Methods - Original API preserved with deprecation warnings
  • Gradual Migration - Optional adoption of new patterns

Installation

go get github.com/mrxinu/gosolar

Requirements: Go 1.21+

Quick Start

Modern Usage (Recommended)

package main
import (
 "context"
 "encoding/json"
 "fmt"
 "log"
 "os"
 "time"
 "github.com/mrxinu/gosolar"
)
func main() {
 // Configuration-based client creation
 config := gosolar.DefaultConfig()
 config.Host = "solarwinds.example.com"
 config.Username = "admin"
 config.Password = os.Getenv("SOLARWINDS_PASSWORD")
 config.Timeout = 30 * time.Second
 client, err := gosolar.NewClient(config)
 if err != nil {
 log.Fatal(err)
 }
 // Context-aware operations
 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 defer cancel()
 // Execute query with context
 result, err := client.QueryContext(ctx, "SELECT NodeID, Caption, IPAddress FROM Orion.Nodes", nil)
 if err != nil {
 // Structured error handling
 var swErr *gosolar.Error
 if errors.As(err, &swErr) {
 switch swErr.Type {
 case gosolar.ErrorTypeAuthentication:
 log.Fatal("Authentication failed")
 case gosolar.ErrorTypeNetwork:
 log.Fatal("Network error:", swErr.Message)
 }
 }
 log.Fatal(err)
 }
 // Strongly typed results
 queryResult, err := gosolar.UnmarshalQueryResult[gosolar.CommonNode](result)
 if err != nil {
 log.Fatal(err)
 }
 fmt.Printf("Found %d nodes:\n", queryResult.Count)
 for _, node := range queryResult.Results {
 fmt.Printf("- %s (%s)\n", node.Caption, node.IPAddress)
 }
}

Legacy Usage (Backward Compatible)

package main
import (
 "encoding/json"
 "fmt"
 "log"
 "github.com/mrxinu/gosolar"
)
func main() {
 // Original API still works
 client, err := gosolar.NewClientLegacy("localhost", "admin", "password", true)
 if err != nil {
 log.Fatal(err)
 }
 res, err := client.Query("SELECT Caption, IPAddress FROM Orion.Nodes", nil)
 if err != nil {
 log.Fatal(err)
 }
 var nodes []struct {
 Caption string `json:"caption"`
 IPAddress string `json:"ipaddress"`
 }
 if err := json.Unmarshal(res, &nodes); err != nil {
 log.Fatal(err)
 }
 for _, n := range nodes {
 fmt.Printf("Node: %s (%s)\n", n.Caption, n.IPAddress)
 }
}

Core Operations

SWQL Queries

// Basic query
result, err := client.QueryContext(ctx, "SELECT * FROM Orion.Nodes", nil)
// Parameterized query
params := map[string]interface{}{
 "vendor": "Cisco",
 "status": 1,
}
result, err := client.QueryContext(ctx, "SELECT * FROM Orion.Nodes WHERE Vendor = @vendor AND Status = @status", params)
// Query helpers
value, err := client.QueryOneContext(ctx, "SELECT COUNT(*) FROM Orion.Nodes", nil)
row, err := client.QueryRowContext(ctx, "SELECT * FROM Orion.Nodes WHERE NodeID = 1", nil)
column, err := client.QueryColumnContext(ctx, "SELECT Caption FROM Orion.Nodes", nil)

CRUD Operations

// Read entity
data, err := client.ReadContext(ctx, "swis://server/Orion/Orion.Nodes/NodeID=1")
// Create entity
props := map[string]interface{}{
 "IPAddress": "192.168.1.1",
 "Caption": "New Node",
}
result, err := client.CreateContext(ctx, "Orion.Nodes", props)
// Update entity
updates := map[string]interface{}{"Caption": "Updated Node"}
result, err := client.UpdateContext(ctx, "swis://server/Orion/Orion.Nodes/NodeID=1", updates)
// Delete entity
result, err := client.DeleteContext(ctx, "swis://server/Orion/Orion.Nodes/NodeID=1")

Custom Properties

// Set single property
err := client.SetCustomPropertyContext(ctx, nodeURI, "Site_Name", "Data Center 1")
// Set multiple properties
props := map[string]interface{}{
 "Site_Name": "Data Center 1",
 "Environment": "Production",
}
err := client.SetCustomPropertiesContext(ctx, nodeURI, props)
// Bulk set property on multiple entities
uris := []string{nodeURI1, nodeURI2, nodeURI3}
err := client.BulkSetCustomPropertyContext(ctx, uris, "Site_Name", "Data Center 1")
// Create custom property definition
req := gosolar.CreateCustomPropertyRequest{
 Entity: "Orion.Nodes",
 Name: "Site_Name",
 Description: "Physical site location",
 Type: gosolar.CustomPropertyTypeString,
 Length: 100,
}
err := client.CreateCustomPropertyContext(ctx, req)

Configuration

Environment Variables

export SOLARWINDS_HOST="your-server.com"
export SOLARWINDS_USERNAME="admin"
export SOLARWINDS_PASSWORD="your-password"

Advanced Configuration

config := gosolar.DefaultConfig()
config.Host = "solarwinds.example.com"
config.Username = "admin"
config.Password = os.Getenv("SOLARWINDS_PASSWORD")
config.Timeout = 30 * time.Second
config.MaxRetries = 3
config.RetryDelay = time.Second
config.MaxIdleConns = 10
config.InsecureSkipVerify = false // Use proper certificates in production
config.UserAgent = "MyApp/1.0"
// Optional: Custom logger
config.Logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
client, err := gosolar.NewClient(config)

Error Handling

result, err := client.QueryContext(ctx, "SELECT * FROM Orion.Nodes", nil)
if err != nil {
 var swErr *gosolar.Error
 if errors.As(err, &swErr) {
 switch swErr.Type {
 case gosolar.ErrorTypeAuthentication:
 // Handle authentication errors
 case gosolar.ErrorTypePermission:
 // Handle permission errors
 case gosolar.ErrorTypeNetwork:
 // Handle network errors
 case gosolar.ErrorTypeSWQL:
 // Handle SWQL syntax errors
 case gosolar.ErrorTypeNotFound:
 // Handle not found errors
 case gosolar.ErrorTypeValidation:
 // Handle validation errors
 case gosolar.ErrorTypeInternal:
 // Handle internal server errors
 }
 fmt.Printf("Error: %s (Type: %s, Status: %d)\n",
 swErr.Message, swErr.Type, swErr.StatusCode)
 }
}

Predefined Types

// Common SolarWinds entities
var nodes []gosolar.CommonNode
var interfaces []gosolar.Interface
var alerts []gosolar.Alert
var volumes []gosolar.Volume
var applications []gosolar.Application
// Status constants
if node.Status == gosolar.NodeStatusUp {
 fmt.Println("Node is up")
}
if alert.Severity == gosolar.AlertSeverityCritical {
 fmt.Println("Critical alert")
}

Testing

Run the comprehensive test suite:

# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run specific test
go test -run TestNewClient

Migration from v1

See MODERNIZATION.md for detailed migration instructions.

Quick Migration

  1. No immediate changes required - existing code continues to work
  2. Gradual adoption - use new patterns for new code
  3. Update when convenient - migrate existing code over time

Key Changes

  • Client creation: NewClient(config) vs NewClientLegacy(host, user, pass, ssl)
  • Context methods: QueryContext(ctx, ...) vs Query(...)
  • Error handling: Structured errors vs string errors

Examples

See the examples directory for working examples:

Documentation

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass: go test ./...
  5. Submit a pull request

License

See LICENSE.md for license information.

Bugs and Issues

Please create an issue on GitHub with details about bugs and steps to reproduce them.

About

A SolarWinds client written in Go.

Topics

Resources

License

Stars

Watchers

Forks

Packages

Contributors

Languages

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /