...
This commit is contained in:
94
pkg/sal/executor/executor.go
Normal file
94
pkg/sal/executor/executor.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package executor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Job represents a command execution job
|
||||
type Job struct {
|
||||
ID string
|
||||
Command string
|
||||
Args []string
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
Status string
|
||||
Output string
|
||||
Error string
|
||||
}
|
||||
|
||||
// Executor handles command execution
|
||||
type Executor struct {
|
||||
jobs map[string]*Job
|
||||
jobsLock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewExecutor creates a new executor instance
|
||||
func NewExecutor() *Executor {
|
||||
return &Executor{
|
||||
jobs: make(map[string]*Job),
|
||||
}
|
||||
}
|
||||
|
||||
// ExecuteCommand runs a command and returns a job ID
|
||||
func (e *Executor) ExecuteCommand(command string, args []string) (string, error) {
|
||||
job := &Job{
|
||||
ID: fmt.Sprintf("job-%d", time.Now().UnixNano()),
|
||||
Command: command,
|
||||
Args: args,
|
||||
StartTime: time.Now(),
|
||||
Status: "running",
|
||||
}
|
||||
|
||||
e.jobsLock.Lock()
|
||||
e.jobs[job.ID] = job
|
||||
e.jobsLock.Unlock()
|
||||
|
||||
go func() {
|
||||
cmd := exec.Command(command, args...)
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
e.jobsLock.Lock()
|
||||
defer e.jobsLock.Unlock()
|
||||
|
||||
job.EndTime = time.Now()
|
||||
job.Output = string(output)
|
||||
|
||||
if err != nil {
|
||||
job.Status = "failed"
|
||||
job.Error = err.Error()
|
||||
} else {
|
||||
job.Status = "completed"
|
||||
}
|
||||
}()
|
||||
|
||||
return job.ID, nil
|
||||
}
|
||||
|
||||
// GetJob returns information about a specific job
|
||||
func (e *Executor) GetJob(jobID string) (*Job, error) {
|
||||
e.jobsLock.RLock()
|
||||
defer e.jobsLock.RUnlock()
|
||||
|
||||
job, exists := e.jobs[jobID]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("job not found: %s", jobID)
|
||||
}
|
||||
|
||||
return job, nil
|
||||
}
|
||||
|
||||
// ListJobs returns all jobs
|
||||
func (e *Executor) ListJobs() []*Job {
|
||||
e.jobsLock.RLock()
|
||||
defer e.jobsLock.RUnlock()
|
||||
|
||||
jobs := make([]*Job, 0, len(e.jobs))
|
||||
for _, job := range e.jobs {
|
||||
jobs = append(jobs, job)
|
||||
}
|
||||
|
||||
return jobs
|
||||
}
|
125
pkg/sal/packagemanager/packagemanager.go
Normal file
125
pkg/sal/packagemanager/packagemanager.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package packagemanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PackageManager handles package installation across different platforms
|
||||
type PackageManager struct {
|
||||
platform string
|
||||
}
|
||||
|
||||
// NewPackageManager creates a new package manager instance
|
||||
func NewPackageManager() *PackageManager {
|
||||
return &PackageManager{
|
||||
platform: runtime.GOOS,
|
||||
}
|
||||
}
|
||||
|
||||
// InstallPackage installs a package using the appropriate package manager
|
||||
func (pm *PackageManager) InstallPackage(packageName string) (string, error) {
|
||||
var cmd *exec.Cmd
|
||||
|
||||
switch pm.platform {
|
||||
case "darwin":
|
||||
// macOS - use Homebrew
|
||||
cmd = exec.Command("brew", "install", packageName)
|
||||
case "linux":
|
||||
// Linux - use apt
|
||||
cmd = exec.Command("apt", "install", "-y", packageName)
|
||||
case "windows":
|
||||
// Windows - use scoop
|
||||
cmd = exec.Command("scoop", "install", packageName)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported platform: %s", pm.platform)
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
return string(output), err
|
||||
}
|
||||
|
||||
// UninstallPackage removes a package
|
||||
func (pm *PackageManager) UninstallPackage(packageName string) (string, error) {
|
||||
var cmd *exec.Cmd
|
||||
|
||||
switch pm.platform {
|
||||
case "darwin":
|
||||
cmd = exec.Command("brew", "uninstall", packageName)
|
||||
case "linux":
|
||||
cmd = exec.Command("apt", "remove", "-y", packageName)
|
||||
case "windows":
|
||||
cmd = exec.Command("scoop", "uninstall", packageName)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported platform: %s", pm.platform)
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
return string(output), err
|
||||
}
|
||||
|
||||
// ListInstalledPackages returns a list of installed packages
|
||||
func (pm *PackageManager) ListInstalledPackages() ([]string, error) {
|
||||
var cmd *exec.Cmd
|
||||
|
||||
switch pm.platform {
|
||||
case "darwin":
|
||||
cmd = exec.Command("brew", "list")
|
||||
case "linux":
|
||||
cmd = exec.Command("apt", "list", "--installed")
|
||||
case "windows":
|
||||
cmd = exec.Command("scoop", "list")
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported platform: %s", pm.platform)
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Parse output into a list of packages
|
||||
packages := strings.Split(string(output), "\n")
|
||||
var result []string
|
||||
for _, pkg := range packages {
|
||||
if pkg = strings.TrimSpace(pkg); pkg != "" {
|
||||
result = append(result, pkg)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// SearchPackage searches for a package
|
||||
func (pm *PackageManager) SearchPackage(query string) ([]string, error) {
|
||||
var cmd *exec.Cmd
|
||||
|
||||
switch pm.platform {
|
||||
case "darwin":
|
||||
cmd = exec.Command("brew", "search", query)
|
||||
case "linux":
|
||||
cmd = exec.Command("apt", "search", query)
|
||||
case "windows":
|
||||
cmd = exec.Command("scoop", "search", query)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported platform: %s", pm.platform)
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Parse output into a list of packages
|
||||
packages := strings.Split(string(output), "\n")
|
||||
var result []string
|
||||
for _, pkg := range packages {
|
||||
if pkg = strings.TrimSpace(pkg); pkg != "" {
|
||||
result = append(result, pkg)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
281
pkg/sal/vm/manager.go
Normal file
281
pkg/sal/vm/manager.go
Normal file
@@ -0,0 +1,281 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Manager handles VM operations
|
||||
type Manager struct {
|
||||
vms map[string]*VM
|
||||
}
|
||||
|
||||
// VM represents a virtual machine
|
||||
type VM struct {
|
||||
Name string
|
||||
CPU int
|
||||
Memory string
|
||||
Disks []Disk
|
||||
Description string
|
||||
Running bool
|
||||
}
|
||||
|
||||
// Disk represents a VM disk
|
||||
type Disk struct {
|
||||
Name string
|
||||
Size string
|
||||
Type string
|
||||
}
|
||||
|
||||
// NewManager creates a new VM manager
|
||||
func NewManager() *Manager {
|
||||
return &Manager{
|
||||
vms: make(map[string]*VM),
|
||||
}
|
||||
}
|
||||
|
||||
// Define creates a new VM definition
|
||||
func (m *Manager) Define(params Params) string {
|
||||
log.Printf("VM Manager: Define called with params: %v", params)
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Check if VM already exists
|
||||
if _, exists := m.vms[name]; exists {
|
||||
return fmt.Sprintf("Error: VM '%s' already exists", name)
|
||||
}
|
||||
|
||||
// Create new VM
|
||||
cpu := params.GetInt("cpu")
|
||||
if cpu <= 0 {
|
||||
cpu = 1
|
||||
}
|
||||
|
||||
memory := params.Get("memory")
|
||||
if memory == "" {
|
||||
memory = "1GB"
|
||||
}
|
||||
|
||||
description := params.Get("description")
|
||||
|
||||
vm := &VM{
|
||||
Name: name,
|
||||
CPU: cpu,
|
||||
Memory: memory,
|
||||
Description: description,
|
||||
Disks: []Disk{},
|
||||
Running: false,
|
||||
}
|
||||
|
||||
// Add VM to map
|
||||
m.vms[name] = vm
|
||||
|
||||
return fmt.Sprintf("VM '%s' defined successfully with %d CPU(s) and %s memory",
|
||||
name, cpu, memory)
|
||||
}
|
||||
|
||||
// Start starts a VM
|
||||
func (m *Manager) Start(params Params) string {
|
||||
log.Printf("VM Manager: Start called with params: %v", params)
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := m.vms[name]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", name)
|
||||
}
|
||||
|
||||
// Check if already running
|
||||
if vm.Running {
|
||||
return fmt.Sprintf("VM '%s' is already running", name)
|
||||
}
|
||||
|
||||
// Start VM
|
||||
vm.Running = true
|
||||
return fmt.Sprintf("VM '%s' started successfully", name)
|
||||
}
|
||||
|
||||
// Stop stops a VM
|
||||
func (m *Manager) Stop(params Params) string {
|
||||
log.Printf("VM Manager: Stop called with params: %v", params)
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := m.vms[name]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", name)
|
||||
}
|
||||
|
||||
// Check if already stopped
|
||||
if !vm.Running {
|
||||
return fmt.Sprintf("VM '%s' is already stopped", name)
|
||||
}
|
||||
|
||||
// Stop VM
|
||||
vm.Running = false
|
||||
return fmt.Sprintf("VM '%s' stopped successfully", name)
|
||||
}
|
||||
|
||||
// DiskAdd adds a disk to a VM
|
||||
func (m *Manager) DiskAdd(params Params) string {
|
||||
log.Printf("VM Manager: DiskAdd called with params: %v", params)
|
||||
|
||||
vmName := params.Get("name")
|
||||
if vmName == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := m.vms[vmName]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", vmName)
|
||||
}
|
||||
|
||||
// Get disk parameters
|
||||
diskName := params.Get("disk_name")
|
||||
if diskName == "" {
|
||||
return "Error: Disk name is required"
|
||||
}
|
||||
|
||||
// Check if disk already exists
|
||||
for _, disk := range vm.Disks {
|
||||
if disk.Name == diskName {
|
||||
return fmt.Sprintf("Error: Disk '%s' already exists on VM '%s'", diskName, vmName)
|
||||
}
|
||||
}
|
||||
|
||||
// Create new disk
|
||||
size := params.Get("size")
|
||||
if size == "" {
|
||||
size = "10GB"
|
||||
}
|
||||
|
||||
diskType := params.Get("type")
|
||||
if diskType == "" {
|
||||
diskType = "ssd"
|
||||
}
|
||||
|
||||
disk := Disk{
|
||||
Name: diskName,
|
||||
Size: size,
|
||||
Type: diskType,
|
||||
}
|
||||
|
||||
// Add disk to VM
|
||||
vm.Disks = append(vm.Disks, disk)
|
||||
|
||||
return fmt.Sprintf("Disk '%s' added to VM '%s' with size %s and type %s",
|
||||
diskName, vmName, size, diskType)
|
||||
}
|
||||
|
||||
// Delete deletes a VM
|
||||
func (m *Manager) Delete(params Params) string {
|
||||
log.Printf("VM Manager: Delete called with params: %v", params)
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := m.vms[name]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", name)
|
||||
}
|
||||
|
||||
// Check if VM is running and force flag is not set
|
||||
if vm.Running && !params.GetBool("force") {
|
||||
return fmt.Sprintf("Error: VM '%s' is running. Use force:true to delete anyway", name)
|
||||
}
|
||||
|
||||
// Delete VM
|
||||
delete(m.vms, name)
|
||||
return fmt.Sprintf("VM '%s' deleted successfully", name)
|
||||
}
|
||||
|
||||
// List returns a list of all VMs
|
||||
func (m *Manager) List() string {
|
||||
log.Printf("VM Manager: List called")
|
||||
|
||||
if len(m.vms) == 0 {
|
||||
return "No VMs defined"
|
||||
}
|
||||
|
||||
var result string
|
||||
result = "Defined VMs:\n"
|
||||
|
||||
for _, vm := range m.vms {
|
||||
status := "stopped"
|
||||
if vm.Running {
|
||||
status = "running"
|
||||
}
|
||||
|
||||
result += fmt.Sprintf("- %s (%s): %d CPU, %s memory\n",
|
||||
vm.Name, status, vm.CPU, vm.Memory)
|
||||
|
||||
if vm.Description != "" {
|
||||
result += fmt.Sprintf(" Description: %s\n", vm.Description)
|
||||
}
|
||||
|
||||
if len(vm.Disks) > 0 {
|
||||
result += " Disks:\n"
|
||||
for _, disk := range vm.Disks {
|
||||
result += fmt.Sprintf(" - %s: %s %s\n",
|
||||
disk.Name, disk.Size, disk.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Status returns the status of a VM
|
||||
func (m *Manager) Status(params Params) string {
|
||||
log.Printf("VM Manager: Status called with params: %v", params)
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := m.vms[name]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", name)
|
||||
}
|
||||
|
||||
// Get VM status
|
||||
status := "stopped"
|
||||
if vm.Running {
|
||||
status = "running"
|
||||
}
|
||||
|
||||
result := fmt.Sprintf("VM '%s' status: %s\n", vm.Name, status)
|
||||
result += fmt.Sprintf("CPU: %d\n", vm.CPU)
|
||||
result += fmt.Sprintf("Memory: %s\n", vm.Memory)
|
||||
|
||||
if vm.Description != "" {
|
||||
result += fmt.Sprintf("Description: %s\n", vm.Description)
|
||||
}
|
||||
|
||||
if len(vm.Disks) > 0 {
|
||||
result += "Disks:\n"
|
||||
for _, disk := range vm.Disks {
|
||||
result += fmt.Sprintf("- %s: %s %s\n",
|
||||
disk.Name, disk.Size, disk.Type)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
38
pkg/sal/vm/params.go
Normal file
38
pkg/sal/vm/params.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Params is a simple helper for working with parameter maps
|
||||
type Params map[string]string
|
||||
|
||||
// Get returns the value for a key
|
||||
func (p Params) Get(key string) string {
|
||||
if val, ok := p[key]; ok {
|
||||
return val
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetInt returns the value for a key as an integer
|
||||
func (p Params) GetInt(key string) int {
|
||||
val := p.Get(key)
|
||||
if val == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
i, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// GetBool returns the value for a key as a boolean
|
||||
func (p Params) GetBool(key string) bool {
|
||||
val := strings.ToLower(p.Get(key))
|
||||
return val == "true" || val == "1" || val == "yes" || val == "y"
|
||||
}
|
Reference in New Issue
Block a user