...
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