...
This commit is contained in:
75
_pkg2_dont_use/heroscript/cmd/fakehandler_start/main.go
Normal file
75
_pkg2_dont_use/heroscript/cmd/fakehandler_start/main.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Parse command line flags
|
||||
socketPath := flag.String("socket", "/tmp/hero.sock", "Unix socket path")
|
||||
tcpAddress := flag.String("tcp", "localhost:8023", "TCP address")
|
||||
useUnixSocket := flag.Bool("unix", true, "Use Unix socket")
|
||||
useTCP := flag.Bool("tcp-enable", false, "Use TCP")
|
||||
flag.Parse()
|
||||
|
||||
// Initialize the hero handler
|
||||
err := herohandler.Init()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to initialize hero handler: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Get the default instance
|
||||
handler := herohandler.DefaultInstance
|
||||
|
||||
// The fake handler is already registered in the Init() function
|
||||
fmt.Println("Using pre-registered fake handler")
|
||||
|
||||
// Start the server
|
||||
if *useUnixSocket || *useTCP {
|
||||
fmt.Printf("Starting telnet server\n")
|
||||
var socketPathStr, tcpAddressStr string
|
||||
if *useUnixSocket {
|
||||
socketPathStr = *socketPath
|
||||
fmt.Printf("Unix socket: %s\n", socketPathStr)
|
||||
}
|
||||
if *useTCP {
|
||||
tcpAddressStr = *tcpAddress
|
||||
fmt.Printf("TCP address: %s\n", tcpAddressStr)
|
||||
}
|
||||
|
||||
err = handler.StartTelnet(socketPathStr, tcpAddressStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to start telnet server: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Print available commands
|
||||
factory := handler.GetFactory()
|
||||
actions := factory.GetSupportedActions()
|
||||
fmt.Println("\nAvailable commands:")
|
||||
for actor, commands := range actions {
|
||||
fmt.Printf("Actor: %s\n", actor)
|
||||
for _, command := range commands {
|
||||
fmt.Printf(" !!%s.%s\n", actor, command)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("\nServer is running. Press Ctrl+C to stop.")
|
||||
|
||||
// Wait for interrupt signal
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigCh
|
||||
|
||||
fmt.Println("\nShutting down...")
|
||||
handler.StopTelnet()
|
||||
fmt.Println("Server stopped")
|
||||
}
|
1
_pkg2_dont_use/heroscript/cmd/heroexecute/.gitignore
vendored
Normal file
1
_pkg2_dont_use/heroscript/cmd/heroexecute/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
heroexecute
|
165
_pkg2_dont_use/heroscript/cmd/heroexecute/main.go
Normal file
165
_pkg2_dont_use/heroscript/cmd/heroexecute/main.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Define command line flags
|
||||
parseCmd := flag.NewFlagSet("parse", flag.ExitOnError)
|
||||
parseFile := parseCmd.String("file", "", "Path to heroscript file to parse")
|
||||
parseText := parseCmd.String("text", "", "Heroscript text to parse")
|
||||
parsePriority := parseCmd.Int("priority", 10, "Default priority for actions")
|
||||
|
||||
executeCmd := flag.NewFlagSet("execute", flag.ExitOnError)
|
||||
executeFile := executeCmd.String("file", "", "Path to heroscript file to execute")
|
||||
executeText := executeCmd.String("text", "", "Heroscript text to execute")
|
||||
executePriority := executeCmd.Int("priority", 10, "Default priority for actions")
|
||||
executeActor := executeCmd.String("actor", "", "Only execute actions for this actor")
|
||||
executeAction := executeCmd.String("action", "", "Only execute actions with this name")
|
||||
|
||||
// Check if a subcommand is provided
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Println("Expected 'parse' or 'execute' subcommand")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Parse the subcommand
|
||||
switch os.Args[1] {
|
||||
case "parse":
|
||||
parseCmd.Parse(os.Args[2:])
|
||||
handleParseCommand(*parseFile, *parseText, *parsePriority)
|
||||
case "execute":
|
||||
executeCmd.Parse(os.Args[2:])
|
||||
handleExecuteCommand(*executeFile, *executeText, *executePriority, *executeActor, *executeAction)
|
||||
default:
|
||||
fmt.Println("Expected 'parse' or 'execute' subcommand")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func handleParseCommand(file, text string, priority int) {
|
||||
var pb *playbook.PlayBook
|
||||
var err error
|
||||
|
||||
// Parse from file or text
|
||||
if file != "" {
|
||||
content, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read file: %v", err)
|
||||
}
|
||||
pb, err = playbook.NewFromText(string(content))
|
||||
} else if text != "" {
|
||||
pb, err = playbook.NewFromText(text)
|
||||
} else {
|
||||
log.Fatalf("Either -file or -text must be provided")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse heroscript: %v", err)
|
||||
}
|
||||
|
||||
// Print the parsed playbook
|
||||
fmt.Printf("Parsed %d actions:\n\n", len(pb.Actions))
|
||||
for i, action := range pb.Actions {
|
||||
fmt.Printf("Action %d: %s.%s (Priority: %d)\n", i+1, action.Actor, action.Name, action.Priority)
|
||||
if action.Comments != "" {
|
||||
fmt.Printf(" Comments: %s\n", action.Comments)
|
||||
}
|
||||
fmt.Printf(" Parameters:\n")
|
||||
for key, value := range action.Params.GetAll() {
|
||||
// Format multiline values
|
||||
if strings.Contains(value, "\n") {
|
||||
fmt.Printf(" %s: |\n", key)
|
||||
lines := strings.Split(value, "\n")
|
||||
for _, line := range lines {
|
||||
fmt.Printf(" %s\n", line)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" %s: %s\n", key, value)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Print the generated heroscript
|
||||
fmt.Println("Generated HeroScript:")
|
||||
fmt.Println("---------------------")
|
||||
fmt.Println(pb.HeroScript(true))
|
||||
fmt.Println("---------------------")
|
||||
}
|
||||
|
||||
func handleExecuteCommand(file, text string, priority int, actor, action string) {
|
||||
var pb *playbook.PlayBook
|
||||
var err error
|
||||
|
||||
// Parse from file or text
|
||||
if file != "" {
|
||||
content, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read file: %v", err)
|
||||
}
|
||||
pb, err = playbook.NewFromText(string(content))
|
||||
} else if text != "" {
|
||||
pb, err = playbook.NewFromText(text)
|
||||
} else {
|
||||
log.Fatalf("Either -file or -text must be provided")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse heroscript: %v", err)
|
||||
}
|
||||
|
||||
// Find actions to execute
|
||||
var actionsToExecute []*playbook.Action
|
||||
if actor != "" || action != "" {
|
||||
// Find specific actions
|
||||
actionsToExecute, err = pb.FindActions(0, actor, action, playbook.ActionTypeUnknown)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to find actions: %v", err)
|
||||
}
|
||||
} else {
|
||||
// Execute all actions in priority order
|
||||
actionsToExecute, err = pb.ActionsSorted(false)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to sort actions: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the actions
|
||||
fmt.Printf("Executing %d actions:\n\n", len(actionsToExecute))
|
||||
for i, action := range actionsToExecute {
|
||||
fmt.Printf("Executing action %d: %s.%s\n", i+1, action.Actor, action.Name)
|
||||
|
||||
// In a real implementation, you would have handlers for different actors and actions
|
||||
// For this example, we'll just simulate execution
|
||||
fmt.Printf(" Parameters:\n")
|
||||
for key, value := range action.Params.GetAll() {
|
||||
fmt.Printf(" %s: %s\n", key, value)
|
||||
}
|
||||
|
||||
// Mark the action as done
|
||||
action.Done = true
|
||||
|
||||
// Set some result data
|
||||
action.Result.Set("status", "success")
|
||||
action.Result.Set("execution_time", "0.5s")
|
||||
|
||||
fmt.Printf(" Result: success\n\n")
|
||||
}
|
||||
|
||||
// Check if all actions are done
|
||||
err = pb.EmptyCheck()
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("All actions executed successfully!")
|
||||
}
|
||||
}
|
2
_pkg2_dont_use/heroscript/cmd/herohandler/.gitignore
vendored
Normal file
2
_pkg2_dont_use/heroscript/cmd/herohandler/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
herohandler
|
||||
example
|
106
_pkg2_dont_use/heroscript/cmd/herohandler/README.md
Normal file
106
_pkg2_dont_use/heroscript/cmd/herohandler/README.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# HeroHandler Example
|
||||
|
||||
This package demonstrates how to implement and use a handler for HeroScript in the HeroLauncher project.
|
||||
|
||||
## Overview
|
||||
|
||||
The HeroHandler example provides a simple key-value store implementation that showcases how to:
|
||||
|
||||
1. Create a custom handler that extends the base handler functionality
|
||||
2. Implement action methods that can be called via HeroScript
|
||||
3. Parse parameters from HeroScript actions
|
||||
4. Process and execute HeroScript commands
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
./herohandler/
|
||||
├── README.md # This documentation file
|
||||
├── main.go # Main executable that uses the example handler
|
||||
└── internal/ # Internal package for the example handler implementation
|
||||
└── example_handler.go # Example handler implementation
|
||||
```
|
||||
|
||||
## Handler Actions
|
||||
|
||||
The example handler supports the following actions:
|
||||
|
||||
- `example.set`: Store a key-value pair
|
||||
- Parameters: `key`, `value`
|
||||
- `example.get`: Retrieve a value by key
|
||||
- Parameters: `key`
|
||||
- `example.list`: List all stored key-value pairs
|
||||
- No parameters
|
||||
- `example.delete`: Remove a key-value pair
|
||||
- Parameters: `key`
|
||||
|
||||
## Usage
|
||||
|
||||
You can run the example handler using the provided `main.go`:
|
||||
|
||||
```bash
|
||||
# Build the binary
|
||||
cd pkg/heroscript/cmd/herohandler
|
||||
go build -o herohandler
|
||||
|
||||
# Set a key-value pair
|
||||
./herohandler "example.set key:mykey value:myvalue"
|
||||
|
||||
# Get a value by key
|
||||
./herohandler "example.get key:mykey"
|
||||
|
||||
# List all stored key-value pairs
|
||||
./herohandler "example.list"
|
||||
|
||||
# Delete a key-value pair
|
||||
./herohandler "example.delete key:mykey"
|
||||
```
|
||||
|
||||
### Important Note on State Persistence
|
||||
|
||||
The example handler maintains its key-value store in memory only for the duration of a single command execution. Each time you run the `herohandler` command, a new instance of the handler is created with an empty data store. This is by design to keep the example simple.
|
||||
|
||||
In a real-world application, you would typically implement persistence using a database, file storage, or other mechanisms to maintain state between command executions.
|
||||
|
||||
### Multi-Command Example
|
||||
|
||||
To execute multiple commands in a single script, you can create a HeroScript file and pass it to the handler. For example:
|
||||
|
||||
```bash
|
||||
# Create a script file
|
||||
cat > example.hero << EOF
|
||||
!!example.set key:user value:john
|
||||
!!example.set key:role value:admin
|
||||
!!example.list
|
||||
EOF
|
||||
|
||||
# Run the script
|
||||
cat example.hero | ./herohandler
|
||||
```
|
||||
|
||||
This would process all commands in a single execution, allowing the in-memory state to be shared between commands.
|
||||
|
||||
## Implementation Details
|
||||
|
||||
The example handler demonstrates several important concepts:
|
||||
|
||||
1. **Handler Structure**: The `ExampleHandler` extends the `handlers.BaseHandler` which provides common functionality for all handlers.
|
||||
|
||||
2. **Action Methods**: Each action is implemented as a method on the handler struct (e.g., `Set`, `Get`, `List`, `Delete`).
|
||||
|
||||
3. **Parameter Parsing**: The `ParseParams` method from `BaseHandler` is used to extract parameters from HeroScript.
|
||||
|
||||
4. **Action Execution**: The `Play` method from `BaseHandler` uses reflection to find and call the appropriate method based on the action name.
|
||||
|
||||
5. **In-Memory Storage**: The example handler maintains a simple in-memory key-value store using a map.
|
||||
|
||||
## Extending the Example
|
||||
|
||||
To create your own handler:
|
||||
|
||||
1. Create a new struct that embeds the `handlers.BaseHandler`
|
||||
2. Implement methods for each action your handler will support
|
||||
3. Create a constructor function that initializes your handler with the appropriate actor name
|
||||
4. Use the `Play` method to process HeroScript commands
|
||||
|
||||
For more complex handlers, you might need to add additional fields to store state or configuration.
|
7
_pkg2_dont_use/heroscript/cmd/herohandler/example.hero
Normal file
7
_pkg2_dont_use/heroscript/cmd/herohandler/example.hero
Normal file
@@ -0,0 +1,7 @@
|
||||
!!example.set key:username value:johndoe
|
||||
!!example.set key:email value:john@example.com
|
||||
!!example.set key:role value:admin
|
||||
!!example.list
|
||||
!!example.get key:username
|
||||
!!example.delete key:email
|
||||
!!example.list
|
@@ -0,0 +1,102 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlers"
|
||||
)
|
||||
|
||||
// ExampleHandler handles example actions
|
||||
type ExampleHandler struct {
|
||||
handlers.BaseHandler
|
||||
data map[string]string
|
||||
}
|
||||
|
||||
// NewExampleHandler creates a new example handler
|
||||
func NewExampleHandler() *ExampleHandler {
|
||||
return &ExampleHandler{
|
||||
BaseHandler: handlers.BaseHandler{
|
||||
BaseHandler: handlerfactory.BaseHandler{
|
||||
ActorName: "example",
|
||||
},
|
||||
},
|
||||
data: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// Set handles the example.set action
|
||||
func (h *ExampleHandler) Set(script string) string {
|
||||
params, err := h.BaseHandler.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
key := params.Get("key")
|
||||
if key == "" {
|
||||
return "Error: key is required"
|
||||
}
|
||||
|
||||
value := params.Get("value")
|
||||
if value == "" {
|
||||
return "Error: value is required"
|
||||
}
|
||||
|
||||
h.data[key] = value
|
||||
return fmt.Sprintf("Set %s = %s", key, value)
|
||||
}
|
||||
|
||||
// Get handles the example.get action
|
||||
func (h *ExampleHandler) Get(script string) string {
|
||||
params, err := h.BaseHandler.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
key := params.Get("key")
|
||||
if key == "" {
|
||||
return "Error: key is required"
|
||||
}
|
||||
|
||||
value, exists := h.data[key]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Key '%s' not found", key)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s = %s", key, value)
|
||||
}
|
||||
|
||||
// List handles the example.list action
|
||||
func (h *ExampleHandler) List(script string) string {
|
||||
if len(h.data) == 0 {
|
||||
return "No data stored"
|
||||
}
|
||||
|
||||
var result string
|
||||
for key, value := range h.data {
|
||||
result += fmt.Sprintf("%s = %s\n", key, value)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Delete handles the example.delete action
|
||||
func (h *ExampleHandler) Delete(script string) string {
|
||||
params, err := h.BaseHandler.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
key := params.Get("key")
|
||||
if key == "" {
|
||||
return "Error: key is required"
|
||||
}
|
||||
|
||||
_, exists := h.data[key]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Key '%s' not found", key)
|
||||
}
|
||||
|
||||
delete(h.data, key)
|
||||
return fmt.Sprintf("Deleted key '%s'", key)
|
||||
}
|
101
_pkg2_dont_use/heroscript/cmd/herohandler/main.go
Normal file
101
_pkg2_dont_use/heroscript/cmd/herohandler/main.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/cmd/herohandler/internal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a new example handler
|
||||
handler := internal.NewExampleHandler()
|
||||
|
||||
// Check if input is coming from stdin (piped input)
|
||||
stat, _ := os.Stdin.Stat()
|
||||
if (stat.Mode() & os.ModeCharDevice) == 0 {
|
||||
// Reading from stdin (pipe or redirect)
|
||||
processStdin(handler)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if there are command-line arguments
|
||||
if len(os.Args) < 2 {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
|
||||
// Get the command from arguments
|
||||
command := strings.Join(os.Args[1:], " ")
|
||||
|
||||
// Format as proper HeroScript with !! prefix if not already prefixed
|
||||
script := command
|
||||
if !strings.HasPrefix(script, "!!") {
|
||||
script = "!!" + script
|
||||
}
|
||||
|
||||
// Process the script
|
||||
result, err := handler.Play(script, handler)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Print the result
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
func printUsage() {
|
||||
fmt.Println("Usage: herohandler <action>")
|
||||
fmt.Println(" cat script.hero | herohandler")
|
||||
fmt.Println("\nExample commands:")
|
||||
fmt.Println(" example.set key:mykey value:myvalue")
|
||||
fmt.Println(" example.get key:mykey")
|
||||
fmt.Println(" example.list")
|
||||
fmt.Println(" example.delete key:mykey")
|
||||
fmt.Println("\nNote: The command will be automatically formatted as HeroScript with !! prefix.")
|
||||
fmt.Println(" You can also pipe a multi-line HeroScript file to process multiple commands.")
|
||||
}
|
||||
|
||||
// processStdin reads and processes HeroScript from stdin
|
||||
func processStdin(handler *internal.ExampleHandler) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
var scriptBuilder strings.Builder
|
||||
|
||||
// Read all lines from stdin
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil && err != io.EOF {
|
||||
fmt.Printf("Error reading from stdin: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Add the line to our script
|
||||
scriptBuilder.WriteString(line)
|
||||
|
||||
// If we've reached EOF, break
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Process the complete script
|
||||
script := scriptBuilder.String()
|
||||
if script == "" {
|
||||
fmt.Println("Error: Empty script")
|
||||
return
|
||||
}
|
||||
|
||||
// Process the script
|
||||
result, err := handler.Play(script, handler)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Print the result
|
||||
fmt.Println(result)
|
||||
}
|
208
_pkg2_dont_use/heroscript/cmd/herohandler_start/main.go
Normal file
208
_pkg2_dont_use/heroscript/cmd/herohandler_start/main.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Start the herohandler in a goroutine
|
||||
go startHeroHandler()
|
||||
|
||||
// Run a simple telnet test
|
||||
time.Sleep(1 * time.Second) // Give the server time to start
|
||||
fmt.Println("\n=== Testing HeroHandler Telnet Server ===")
|
||||
fmt.Println("The herohandler is running with a process manager handler registered.")
|
||||
fmt.Println("You can connect to the telnet server at:")
|
||||
fmt.Println("- Unix socket: /tmp/hero.sock")
|
||||
fmt.Println("- TCP address: localhost:8023")
|
||||
fmt.Println("\nYou can use the following command to connect:")
|
||||
fmt.Println(" telnet localhost 8023")
|
||||
fmt.Println(" nc -U /tmp/hero.sock")
|
||||
|
||||
// Start interactive shell
|
||||
fmt.Println("\n=== Interactive Shell ===")
|
||||
fmt.Println("Type 'help' to see available commands")
|
||||
fmt.Println("Type 'exit' to quit")
|
||||
|
||||
startInteractiveShell()
|
||||
}
|
||||
|
||||
func startInteractiveShell() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Print("> ")
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println("Error reading input:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
input = strings.TrimSpace(input)
|
||||
|
||||
switch input {
|
||||
case "exit", "quit":
|
||||
fmt.Println("Exiting...")
|
||||
// Send termination signal to the herohandler goroutine
|
||||
syscall.Kill(syscall.Getpid(), syscall.SIGINT)
|
||||
return
|
||||
|
||||
case "help":
|
||||
showHelp()
|
||||
|
||||
case "status":
|
||||
fmt.Println("HeroHandler is running")
|
||||
fmt.Println("Telnet server is active at:")
|
||||
fmt.Println("- Unix socket: /tmp/hero.sock")
|
||||
fmt.Println("- TCP address: localhost:8023")
|
||||
|
||||
case "actions":
|
||||
showSupportedActions()
|
||||
|
||||
case "test":
|
||||
runTestScript()
|
||||
|
||||
default:
|
||||
if input != "" {
|
||||
fmt.Println("Unknown command. Type 'help' to see available commands.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showHelp() {
|
||||
fmt.Println("Available commands:")
|
||||
fmt.Println(" help - Show this help message")
|
||||
fmt.Println(" status - Show herohandler status")
|
||||
fmt.Println(" actions - Show supported actions for registered handlers")
|
||||
fmt.Println(" test - Run a test heroscript")
|
||||
fmt.Println(" exit - Exit the program")
|
||||
}
|
||||
|
||||
func showSupportedActions() {
|
||||
// We need to implement this function to get supported actions
|
||||
// Since we can't directly access the factory field, we'll use the telnet interface
|
||||
script := "!!core.actions"
|
||||
|
||||
// Try TCP first, then Unix socket if TCP fails
|
||||
result, err := Send(script, "localhost:8023", false)
|
||||
if err != nil {
|
||||
fmt.Printf("TCP connection failed, trying Unix socket: %v\n", err)
|
||||
result, err = Send(script, "/tmp/hero.sock", true)
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting supported actions: %v\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Supported actions by actor:")
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// Send connects to the telnet server and sends a command, returning the response
|
||||
func Send(command string, address string, isUnixSocket bool) (string, error) {
|
||||
var conn net.Conn
|
||||
var err error
|
||||
|
||||
// Connect to the server based on the address type
|
||||
if isUnixSocket {
|
||||
conn, err = net.Dial("unix", address)
|
||||
} else {
|
||||
conn, err = net.Dial("tcp", address)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error connecting to server: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Create a reader for the connection
|
||||
reader := bufio.NewReader(conn)
|
||||
|
||||
// Read the welcome message
|
||||
_, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error reading welcome message: %v", err)
|
||||
}
|
||||
|
||||
// Send the command
|
||||
fmt.Fprintf(conn, "%s\n", command)
|
||||
|
||||
// Read the response with a timeout
|
||||
result := ""
|
||||
ch := make(chan string)
|
||||
errCh := make(chan error)
|
||||
|
||||
go func() {
|
||||
var response strings.Builder
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("error reading response: %v", err)
|
||||
return
|
||||
}
|
||||
response.WriteString(line)
|
||||
|
||||
// If we've received a complete response, break
|
||||
if strings.Contains(line, "\n") && strings.TrimSpace(line) == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
ch <- response.String()
|
||||
}()
|
||||
|
||||
select {
|
||||
case result = <-ch:
|
||||
return result, nil
|
||||
case err = <-errCh:
|
||||
return "", err
|
||||
case <-time.After(5 * time.Second):
|
||||
return "", fmt.Errorf("timeout waiting for response")
|
||||
}
|
||||
}
|
||||
|
||||
func runTestScript() {
|
||||
// Simple test script for the process manager
|
||||
script := `
|
||||
!!process.list format:json
|
||||
`
|
||||
|
||||
fmt.Println("Running test script:")
|
||||
fmt.Println(script)
|
||||
|
||||
// Send the script to the telnet server
|
||||
// Try TCP first, then Unix socket if TCP fails
|
||||
result, err := Send(script, "localhost:8023", false)
|
||||
if err != nil {
|
||||
fmt.Printf("TCP connection failed, trying Unix socket: %v\n", err)
|
||||
result, err = Send(script, "/tmp/hero.sock", true)
|
||||
if err != nil {
|
||||
fmt.Printf("Unix socket connection failed: %v\n", err)
|
||||
|
||||
// We can't directly access the factory field, so we'll just report the error
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Result:")
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
func startHeroHandler() {
|
||||
if err := herohandler.Init(); err != nil {
|
||||
log.Fatalf("Failed to start telnet server: %v", err)
|
||||
}
|
||||
if err := herohandler.StartTelnet(); err != nil {
|
||||
log.Fatalf("Failed to start telnet server: %v", err)
|
||||
}
|
||||
}
|
1
_pkg2_dont_use/heroscript/cmd/heroscriptexample/.gitignore
vendored
Normal file
1
_pkg2_dont_use/heroscript/cmd/heroscriptexample/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
heroscriptexample
|
75
_pkg2_dont_use/heroscript/cmd/heroscriptexample/main.go
Normal file
75
_pkg2_dont_use/heroscript/cmd/heroscriptexample/main.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
const exampleScript = `
|
||||
//This is a mail client configuration
|
||||
!!mailclient.configure
|
||||
name: 'mymail'
|
||||
host: 'smtp.example.com'
|
||||
port: 25
|
||||
secure: 1
|
||||
reset: 1
|
||||
description: '
|
||||
This is a multiline description
|
||||
for my mail client configuration.
|
||||
|
||||
It supports multiple paragraphs.
|
||||
'
|
||||
|
||||
//System update action
|
||||
!!system.update
|
||||
force: 1
|
||||
packages: 'git,curl,wget'
|
||||
`
|
||||
|
||||
func main() {
|
||||
// Parse heroscript
|
||||
pb, err := playbook.NewFromText(exampleScript)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse heroscript: %v", err)
|
||||
}
|
||||
|
||||
// Print the playbook
|
||||
fmt.Println("Playbook contains:")
|
||||
fmt.Printf("- %d actions\n", len(pb.Actions))
|
||||
fmt.Println("- Hash: " + pb.HashKey())
|
||||
fmt.Println()
|
||||
|
||||
// Print each action
|
||||
for i, action := range pb.Actions {
|
||||
fmt.Printf("Action %d: %s.%s\n", i+1, action.Actor, action.Name)
|
||||
fmt.Printf(" Comments: %s\n", action.Comments)
|
||||
fmt.Printf(" Parameters:\n")
|
||||
|
||||
for key, value := range action.Params.GetAll() {
|
||||
fmt.Printf(" %s: %s\n", key, value)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Generate heroscript
|
||||
fmt.Println("Generated HeroScript:")
|
||||
fmt.Println("---------------------")
|
||||
fmt.Println(pb.HeroScript(true))
|
||||
fmt.Println("---------------------")
|
||||
|
||||
// Demonstrate finding actions
|
||||
mailActions, err := pb.FindActions(0, "mailclient", "", playbook.ActionTypeUnknown)
|
||||
if err != nil {
|
||||
log.Fatalf("Error finding actions: %v", err)
|
||||
}
|
||||
fmt.Printf("\nFound %d mail client actions\n", len(mailActions))
|
||||
|
||||
// Mark an action as done
|
||||
if len(pb.Actions) > 0 {
|
||||
pb.Actions[0].Done = true
|
||||
fmt.Println("\nAfter marking first action as done:")
|
||||
fmt.Println(pb.HeroScript(false)) // Don't show done actions
|
||||
}
|
||||
}
|
19
_pkg2_dont_use/heroscript/cmd/vmhandler/.gitignore
vendored
Normal file
19
_pkg2_dont_use/heroscript/cmd/vmhandler/.gitignore
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
vmhandler
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
134
_pkg2_dont_use/heroscript/cmd/vmhandler/README.md
Normal file
134
_pkg2_dont_use/heroscript/cmd/vmhandler/README.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# VM Handler Example
|
||||
|
||||
This example demonstrates how to use the HandlerFactory with a VM handler to process heroscript commands.
|
||||
|
||||
## Overview
|
||||
|
||||
The VM handler example shows how to:
|
||||
|
||||
1. Create a handler that processes VM-related actions
|
||||
2. Register the handler with the HandlerFactory
|
||||
3. Start a telnet server that uses the HandlerFactory to process commands
|
||||
4. Connect to the telnet server and send heroscript commands
|
||||
|
||||
## Running the Example
|
||||
|
||||
To run the example:
|
||||
|
||||
```bash
|
||||
cd ~/code/github/freeflowuniverse/herocode/heroagent/pkg/handlerfactory/cmd/vmhandler
|
||||
go run . tutorial
|
||||
#to run just the server do
|
||||
go run .
|
||||
#you can then go to other terminal and play with telnet / nc
|
||||
```
|
||||
|
||||
This will start a telnet server on:
|
||||
- Unix socket: `/tmp/vmhandler.sock`
|
||||
- TCP: `localhost:8024`
|
||||
|
||||
## Connecting to the Server
|
||||
|
||||
### Using Unix Socket
|
||||
|
||||
```bash
|
||||
nc -U /tmp/vmhandler.sock
|
||||
```
|
||||
|
||||
### Using TCP
|
||||
|
||||
```bash
|
||||
telnet localhost 8024
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
When you connect, you'll need to authenticate with the secret:
|
||||
|
||||
```
|
||||
!!auth secret:1234
|
||||
```
|
||||
|
||||
## Available Commands
|
||||
|
||||
Once authenticated, you can use the following commands:
|
||||
|
||||
```
|
||||
!!vm.define name:'test_vm' cpu:4 memory:'8GB' storage:'100GB'
|
||||
!!vm.start name:'test_vm'
|
||||
!!vm.stop name:'test_vm'
|
||||
!!vm.disk_add name:'test_vm' size:'50GB' type:'SSD'
|
||||
!!vm.list
|
||||
!!vm.status name:'test_vm'
|
||||
!!vm.delete name:'test_vm' force:true
|
||||
```
|
||||
|
||||
## Example Session
|
||||
|
||||
Here's an example session:
|
||||
|
||||
```
|
||||
$ telnet localhost 8024
|
||||
Connected to localhost.
|
||||
Escape character is '^]'.
|
||||
** Welcome: you are not authenticated, provide secret.
|
||||
!!auth secret:1234
|
||||
|
||||
** Welcome: you are authenticated.
|
||||
!!vm.define name:'test_vm' cpu:4 memory:'8GB' storage:'100GB'
|
||||
VM 'test_vm' defined successfully with 4 CPU, 8GB memory, and 100GB storage
|
||||
|
||||
!!vm.start name:'test_vm'
|
||||
VM 'test_vm' started successfully
|
||||
|
||||
!!vm.disk_add name:'test_vm' size:'50GB' type:'SSD'
|
||||
Added 50GB SSD disk to VM 'test_vm'
|
||||
|
||||
!!vm.status name:'test_vm'
|
||||
VM 'test_vm' status:
|
||||
- Status: running
|
||||
- CPU: 4
|
||||
- Memory: 8GB
|
||||
- Storage: 100GB
|
||||
- Attached disks:
|
||||
1. 50GB SSD
|
||||
|
||||
!!vm.list
|
||||
Defined VMs:
|
||||
- test_vm (running): 4 CPU, 8GB memory, 100GB storage
|
||||
Attached disks:
|
||||
1. 50GB SSD
|
||||
|
||||
!!vm.stop name:'test_vm'
|
||||
VM 'test_vm' stopped successfully
|
||||
|
||||
!!vm.delete name:'test_vm'
|
||||
VM 'test_vm' deleted successfully
|
||||
|
||||
!!quit
|
||||
Goodbye!
|
||||
Connection closed by foreign host.
|
||||
```
|
||||
|
||||
## Other Commands
|
||||
|
||||
- `!!help`, `h`, or `?` - Show help
|
||||
- `!!interactive` or `!!i` - Toggle interactive mode (with colors)
|
||||
- `!!quit`, `!!exit`, or `q` - Disconnect from server
|
||||
|
||||
## How It Works
|
||||
|
||||
1. The `main.go` file creates a HandlerFactory and registers the VM handler
|
||||
2. It starts a telnet server that uses the HandlerFactory to process commands
|
||||
3. When a client connects and sends a heroscript command, the server:
|
||||
- Parses the command to determine the actor and action
|
||||
- Calls the appropriate method on the VM handler
|
||||
- Returns the result to the client
|
||||
|
||||
## Extending the Example
|
||||
|
||||
You can extend this example by:
|
||||
|
||||
1. Adding more methods to the VM handler
|
||||
2. Creating new handlers for different actors
|
||||
3. Registering multiple handlers with the HandlerFactory
|
276
_pkg2_dont_use/heroscript/cmd/vmhandler/tutorial.go
Normal file
276
_pkg2_dont_use/heroscript/cmd/vmhandler/tutorial.go
Normal file
@@ -0,0 +1,276 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// runTutorial runs an interactive tutorial demonstrating the VM handler
|
||||
func runTutorial() {
|
||||
fmt.Println("=== VM Handler Tutorial ===")
|
||||
fmt.Println("This tutorial will demonstrate how to use the VM handler with heroscript commands.")
|
||||
fmt.Println("Press Enter to continue through each step...")
|
||||
waitForEnter()
|
||||
|
||||
// Create a new handler factory
|
||||
fmt.Println("\nStep 1: Create a new HandlerFactory")
|
||||
fmt.Println("factory := handlerfactory.NewHandlerFactory()")
|
||||
factory := handlerfactory.NewHandlerFactory()
|
||||
waitForEnter()
|
||||
|
||||
// Create a VM handler
|
||||
fmt.Println("\nStep 2: Create a VM handler")
|
||||
fmt.Println("vmHandler := NewVMHandler()")
|
||||
vmHandler := NewVMHandler()
|
||||
waitForEnter()
|
||||
|
||||
// Register the VM handler with the factory
|
||||
fmt.Println("\nStep 3: Register the VM handler with the factory")
|
||||
fmt.Println("factory.RegisterHandler(vmHandler)")
|
||||
err := factory.RegisterHandler(vmHandler)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Handler registered successfully!")
|
||||
waitForEnter()
|
||||
|
||||
// Show available actions
|
||||
fmt.Println("\nStep 4: List available actions for the VM handler")
|
||||
actions := factory.GetSupportedActions()
|
||||
fmt.Println("Supported actions for 'vm' actor:")
|
||||
for _, action := range actions["vm"] {
|
||||
fmt.Printf("- %s\n", action)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// Process heroscript commands
|
||||
fmt.Println("\nStep 5: Process heroscript commands")
|
||||
|
||||
// Define a VM
|
||||
defineScript := `!!vm.define name:'tutorial_vm' cpu:2 memory:'4GB' storage:'50GB'
|
||||
description: 'A tutorial VM for demonstration purposes'`
|
||||
fmt.Println("\nCommand:")
|
||||
fmt.Println(defineScript)
|
||||
fmt.Println("\nProcessing...")
|
||||
time.Sleep(1 * time.Second)
|
||||
result, err := factory.ProcessHeroscript(defineScript)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Result: %s\n", result)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// Start the VM
|
||||
startScript := `!!vm.start name:'tutorial_vm'`
|
||||
fmt.Println("\nCommand:")
|
||||
fmt.Println(startScript)
|
||||
fmt.Println("\nProcessing...")
|
||||
time.Sleep(1 * time.Second)
|
||||
result, err = factory.ProcessHeroscript(startScript)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Result: %s\n", result)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// Add a disk
|
||||
diskAddScript := `!!vm.disk_add name:'tutorial_vm' size:'20GB' type:'SSD'`
|
||||
fmt.Println("\nCommand:")
|
||||
fmt.Println(diskAddScript)
|
||||
fmt.Println("\nProcessing...")
|
||||
time.Sleep(1 * time.Second)
|
||||
result, err = factory.ProcessHeroscript(diskAddScript)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Result: %s\n", result)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// Check VM status
|
||||
statusScript := `!!vm.status name:'tutorial_vm'`
|
||||
fmt.Println("\nCommand:")
|
||||
fmt.Println(statusScript)
|
||||
fmt.Println("\nProcessing...")
|
||||
time.Sleep(1 * time.Second)
|
||||
result, err = factory.ProcessHeroscript(statusScript)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Result: %s\n", result)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// List all VMs
|
||||
listScript := `!!vm.list`
|
||||
fmt.Println("\nCommand:")
|
||||
fmt.Println(listScript)
|
||||
fmt.Println("\nProcessing...")
|
||||
time.Sleep(1 * time.Second)
|
||||
result, err = factory.ProcessHeroscript(listScript)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Result: %s\n", result)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// Stop the VM
|
||||
stopScript := `!!vm.stop name:'tutorial_vm'`
|
||||
fmt.Println("\nCommand:")
|
||||
fmt.Println(stopScript)
|
||||
fmt.Println("\nProcessing...")
|
||||
time.Sleep(1 * time.Second)
|
||||
result, err = factory.ProcessHeroscript(stopScript)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Result: %s\n", result)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// Delete the VM
|
||||
deleteScript := `!!vm.delete name:'tutorial_vm'`
|
||||
fmt.Println("\nCommand:")
|
||||
fmt.Println(deleteScript)
|
||||
fmt.Println("\nProcessing...")
|
||||
time.Sleep(1 * time.Second)
|
||||
result, err = factory.ProcessHeroscript(deleteScript)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Result: %s\n", result)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// Try an invalid command
|
||||
invalidScript := `!!vm.invalid name:'tutorial_vm'`
|
||||
fmt.Println("\nInvalid Command:")
|
||||
fmt.Println(invalidScript)
|
||||
fmt.Println("\nProcessing...")
|
||||
time.Sleep(1 * time.Second)
|
||||
result, err = factory.ProcessHeroscript(invalidScript)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Result: %s\n", result)
|
||||
}
|
||||
waitForEnter()
|
||||
|
||||
// Conclusion
|
||||
fmt.Println("\nTutorial Complete!")
|
||||
fmt.Println("You've seen how to:")
|
||||
fmt.Println("1. Create a HandlerFactory")
|
||||
fmt.Println("2. Register a VM handler")
|
||||
fmt.Println("3. Process various heroscript commands")
|
||||
fmt.Println("\nTo run the full telnet server example, execute:")
|
||||
fmt.Println("go run main.go vm_handler.go")
|
||||
fmt.Println("\nPress Enter to exit the tutorial...")
|
||||
waitForEnter()
|
||||
}
|
||||
|
||||
// waitForEnter waits for the user to press Enter
|
||||
func waitForEnter() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
reader.ReadString('\n')
|
||||
}
|
||||
|
||||
// VMTutorial contains the tutorial text for the VM handler
|
||||
const VMTutorial = `
|
||||
VM Handler Tutorial
|
||||
==================
|
||||
|
||||
The VM handler provides a set of commands to manage virtual machines through heroscript commands.
|
||||
|
||||
Available VM commands:
|
||||
!!vm.define name:test_vm cpu:4 memory:8GB storage:100GB
|
||||
!!vm.start name:test_vm
|
||||
!!vm.stop name:test_vm
|
||||
!!vm.disk_add name:test_vm size:50GB type:SSD
|
||||
!!vm.list
|
||||
!!vm.status name:test_vm
|
||||
!!vm.delete name:test_vm force:true
|
||||
|
||||
Authentication secret: 1234
|
||||
|
||||
Command Details:
|
||||
--------------
|
||||
1. define - Create a new VM with specified resources
|
||||
Parameters:
|
||||
- name: (required) Name of the VM
|
||||
- cpu: (optional) Number of CPUs, default: 1
|
||||
- memory: (optional) Memory size, default: 1GB
|
||||
- storage: (optional) Storage size, default: 10GB
|
||||
- description: (optional) Description of the VM
|
||||
|
||||
2. start - Start a VM
|
||||
Parameters:
|
||||
- name: (required) Name of the VM to start
|
||||
|
||||
3. stop - Stop a running VM
|
||||
Parameters:
|
||||
- name: (required) Name of the VM to stop
|
||||
|
||||
4. disk_add - Add a disk to a VM
|
||||
Parameters:
|
||||
- name: (required) Name of the VM
|
||||
- size: (optional) Size of the disk, default: 10GB
|
||||
- type: (optional) Type of disk (SSD, HDD), default: HDD
|
||||
|
||||
5. list - List all VMs
|
||||
|
||||
6. status - Show status of a VM
|
||||
Parameters:
|
||||
- name: (required) Name of the VM
|
||||
|
||||
7. delete - Delete a VM
|
||||
Parameters:
|
||||
- name: (required) Name of the VM
|
||||
- force: (optional) Force deletion even if VM is running, default: false
|
||||
|
||||
8. help - Show this help message
|
||||
|
||||
Examples:
|
||||
--------
|
||||
1. Create a new VM:
|
||||
!!vm.define name:webserver cpu:2 memory:4GB storage:50GB description:'Web server VM'
|
||||
|
||||
2. Start the VM:
|
||||
!!vm.start name:webserver
|
||||
|
||||
3. Add an SSD disk:
|
||||
!!vm.disk_add name:webserver size:100GB type:SSD
|
||||
|
||||
4. Check VM status:
|
||||
!!vm.status name:webserver
|
||||
|
||||
5. List all VMs:
|
||||
!!vm.list
|
||||
|
||||
6. Stop the VM:
|
||||
!!vm.stop name:webserver
|
||||
|
||||
7. Delete the VM:
|
||||
!!vm.delete name:webserver force:true
|
||||
`
|
||||
|
||||
// addTutorialCommand adds the tutorial command to the main function
|
||||
func addTutorialCommand() {
|
||||
// Check command line arguments
|
||||
if len(os.Args) > 1 && os.Args[1] == "tutorial" {
|
||||
runTutorial()
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
// GetVMTutorial returns the VM handler tutorial text
|
||||
func GetVMTutorial() string {
|
||||
return VMTutorial
|
||||
}
|
285
_pkg2_dont_use/heroscript/cmd/vmhandler/vm_handler.go
Normal file
285
_pkg2_dont_use/heroscript/cmd/vmhandler/vm_handler.go
Normal file
@@ -0,0 +1,285 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// VMHandler handles VM-related actions
|
||||
type VMHandler struct {
|
||||
handlerfactory.BaseHandler
|
||||
vms map[string]*VM
|
||||
}
|
||||
|
||||
// VM represents a virtual machine
|
||||
type VM struct {
|
||||
Name string
|
||||
CPU int
|
||||
Memory string
|
||||
Storage string
|
||||
Description string
|
||||
Running bool
|
||||
Disks []Disk
|
||||
}
|
||||
|
||||
// Disk represents a disk attached to a VM
|
||||
type Disk struct {
|
||||
Size string
|
||||
Type string
|
||||
}
|
||||
|
||||
// NewVMHandler creates a new VM handler
|
||||
func NewVMHandler() *VMHandler {
|
||||
return &VMHandler{
|
||||
BaseHandler: handlerfactory.BaseHandler{
|
||||
ActorName: "vm",
|
||||
},
|
||||
vms: make(map[string]*VM),
|
||||
}
|
||||
}
|
||||
|
||||
// Define handles the vm.define action
|
||||
func (h *VMHandler) Define(script string) string {
|
||||
params, err := h.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Check if VM already exists
|
||||
if _, exists := h.vms[name]; exists {
|
||||
return fmt.Sprintf("Error: VM '%s' already exists", name)
|
||||
}
|
||||
|
||||
// Create new VM
|
||||
cpu := params.GetIntDefault("cpu", 1)
|
||||
memory := params.Get("memory")
|
||||
if memory == "" {
|
||||
memory = "1GB"
|
||||
}
|
||||
storage := params.Get("storage")
|
||||
if storage == "" {
|
||||
storage = "10GB"
|
||||
}
|
||||
description := params.Get("description")
|
||||
|
||||
vm := &VM{
|
||||
Name: name,
|
||||
CPU: cpu,
|
||||
Memory: memory,
|
||||
Storage: storage,
|
||||
Description: description,
|
||||
Running: false,
|
||||
Disks: []Disk{},
|
||||
}
|
||||
|
||||
// Add VM to map
|
||||
h.vms[name] = vm
|
||||
|
||||
return fmt.Sprintf("VM '%s' defined successfully with %d CPU, %s memory, and %s storage",
|
||||
name, cpu, memory, storage)
|
||||
}
|
||||
|
||||
// Start handles the vm.start action
|
||||
func (h *VMHandler) Start(script string) string {
|
||||
params, err := h.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := h.vms[name]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", name)
|
||||
}
|
||||
|
||||
// Start VM
|
||||
if vm.Running {
|
||||
return fmt.Sprintf("VM '%s' is already running", name)
|
||||
}
|
||||
|
||||
vm.Running = true
|
||||
return fmt.Sprintf("VM '%s' started successfully", name)
|
||||
}
|
||||
|
||||
// Stop handles the vm.stop action
|
||||
func (h *VMHandler) Stop(script string) string {
|
||||
params, err := h.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := h.vms[name]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", name)
|
||||
}
|
||||
|
||||
// Stop VM
|
||||
if !vm.Running {
|
||||
return fmt.Sprintf("VM '%s' is already stopped", name)
|
||||
}
|
||||
|
||||
vm.Running = false
|
||||
return fmt.Sprintf("VM '%s' stopped successfully", name)
|
||||
}
|
||||
|
||||
// DiskAdd handles the vm.disk_add action
|
||||
func (h *VMHandler) DiskAdd(script string) string {
|
||||
params, err := h.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := h.vms[name]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", name)
|
||||
}
|
||||
|
||||
// Add disk
|
||||
size := params.Get("size")
|
||||
if size == "" {
|
||||
size = "10GB"
|
||||
}
|
||||
diskType := params.Get("type")
|
||||
if diskType == "" {
|
||||
diskType = "HDD"
|
||||
}
|
||||
|
||||
disk := Disk{
|
||||
Size: size,
|
||||
Type: diskType,
|
||||
}
|
||||
|
||||
vm.Disks = append(vm.Disks, disk)
|
||||
return fmt.Sprintf("Added %s %s disk to VM '%s'", size, diskType, name)
|
||||
}
|
||||
|
||||
// Delete handles the vm.delete action
|
||||
func (h *VMHandler) Delete(script string) string {
|
||||
params, err := h.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := h.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(h.vms, name)
|
||||
return fmt.Sprintf("VM '%s' deleted successfully", name)
|
||||
}
|
||||
|
||||
// List handles the vm.list action
|
||||
func (h *VMHandler) List(script string) string {
|
||||
if len(h.vms) == 0 {
|
||||
return "No VMs defined"
|
||||
}
|
||||
|
||||
var result strings.Builder
|
||||
result.WriteString("Defined VMs:\n")
|
||||
|
||||
for _, vm := range h.vms {
|
||||
status := "stopped"
|
||||
if vm.Running {
|
||||
status = "running"
|
||||
}
|
||||
|
||||
result.WriteString(fmt.Sprintf("- %s (%s): %d CPU, %s memory, %s storage\n",
|
||||
vm.Name, status, vm.CPU, vm.Memory, vm.Storage))
|
||||
|
||||
if len(vm.Disks) > 0 {
|
||||
result.WriteString(" Attached disks:\n")
|
||||
for i, disk := range vm.Disks {
|
||||
result.WriteString(fmt.Sprintf(" %d. %s %s\n", i+1, disk.Size, disk.Type))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
// Help handles the vm.help action
|
||||
func (h *VMHandler) Help(script string) string {
|
||||
return GetVMTutorial()
|
||||
}
|
||||
|
||||
// Status handles the vm.status action
|
||||
func (h *VMHandler) Status(script string) string {
|
||||
params, err := h.ParseParams(script)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error parsing parameters: %v", err)
|
||||
}
|
||||
|
||||
name := params.Get("name")
|
||||
if name == "" {
|
||||
return "Error: VM name is required"
|
||||
}
|
||||
|
||||
// Find VM
|
||||
vm, exists := h.vms[name]
|
||||
if !exists {
|
||||
return fmt.Sprintf("Error: VM '%s' not found", name)
|
||||
}
|
||||
|
||||
// Return VM status
|
||||
status := "stopped"
|
||||
if vm.Running {
|
||||
status = "running"
|
||||
}
|
||||
|
||||
var result strings.Builder
|
||||
result.WriteString(fmt.Sprintf("VM '%s' status:\n", name))
|
||||
result.WriteString(fmt.Sprintf("- Status: %s\n", status))
|
||||
result.WriteString(fmt.Sprintf("- CPU: %d\n", vm.CPU))
|
||||
result.WriteString(fmt.Sprintf("- Memory: %s\n", vm.Memory))
|
||||
result.WriteString(fmt.Sprintf("- Storage: %s\n", vm.Storage))
|
||||
|
||||
if vm.Description != "" {
|
||||
result.WriteString(fmt.Sprintf("- Description: %s\n", vm.Description))
|
||||
}
|
||||
|
||||
if len(vm.Disks) > 0 {
|
||||
result.WriteString("- Attached disks:\n")
|
||||
for i, disk := range vm.Disks {
|
||||
result.WriteString(fmt.Sprintf(" %d. %s %s\n", i+1, disk.Size, disk.Type))
|
||||
}
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
75
_pkg2_dont_use/heroscript/cmd/vmhandler/vm_handler_server.go
Normal file
75
_pkg2_dont_use/heroscript/cmd/vmhandler/vm_handler_server.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// The tutorial functions are defined in tutorial.go
|
||||
|
||||
func main() {
|
||||
// Check if tutorial mode is requested
|
||||
addTutorialCommand()
|
||||
|
||||
fmt.Println("Starting VM Handler Example")
|
||||
|
||||
// Create a new handler factory
|
||||
factory := handlerfactory.NewHandlerFactory()
|
||||
|
||||
// Create and register the VM handler
|
||||
vmHandler := NewVMHandler()
|
||||
err := factory.RegisterHandler(vmHandler)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to register VM handler: %v", err)
|
||||
}
|
||||
|
||||
// Create a telnet server with the handler factory
|
||||
server := handlerfactory.NewTelnetServer(factory, "1234")
|
||||
|
||||
// Create socket directory if it doesn't exist
|
||||
socketDir := "/tmp"
|
||||
err = os.MkdirAll(socketDir, 0755)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create socket directory: %v", err)
|
||||
}
|
||||
|
||||
// Start the telnet server on a Unix socket
|
||||
socketPath := filepath.Join(socketDir, "vmhandler.sock")
|
||||
err = server.Start(socketPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to start telnet server: %v", err)
|
||||
}
|
||||
fmt.Printf("Telnet server started on socket: %s\n", socketPath)
|
||||
fmt.Printf("Connect with: nc -U %s\n", socketPath)
|
||||
|
||||
// Also start on TCP port for easier access
|
||||
err = server.StartTCP("localhost:8024")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to start TCP telnet server: %v", err)
|
||||
}
|
||||
fmt.Println("Telnet server started on TCP: localhost:8024")
|
||||
fmt.Println("Connect with: telnet localhost 8024")
|
||||
|
||||
// Print available commands
|
||||
fmt.Println("\nVM Handler started. Type '!!vm.help' to see available commands.")
|
||||
fmt.Println("Authentication secret: 1234")
|
||||
|
||||
// Wait for interrupt signal
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigChan
|
||||
|
||||
// Stop the server
|
||||
fmt.Println("Stopping server...")
|
||||
err = server.Stop()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to stop telnet server: %v", err)
|
||||
}
|
||||
fmt.Println("Telnet server stopped")
|
||||
}
|
Reference in New Issue
Block a user