Compare commits
2 Commits
0d5b7b6939
...
393306de12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
393306de12 | ||
|
|
8d19fbd549 |
@@ -2,3 +2,52 @@
|
|||||||
|
|
||||||
- Go 1.21+
|
- Go 1.21+
|
||||||
- GNU Make (for build automation)
|
- GNU Make (for build automation)
|
||||||
|
|
||||||
|
## Patterns
|
||||||
|
|
||||||
|
### Instance-scoped Commands
|
||||||
|
|
||||||
|
CLI commands that operate on a specific Wild Cloud instance should follow this pattern:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// In cmd/utility.go
|
||||||
|
var dashboardTokenCmd = &cobra.Command{
|
||||||
|
Use: "token",
|
||||||
|
Short: "Get dashboard token",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
// 1. Get instance from CLI context
|
||||||
|
instanceName, err := getInstanceName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Call instance-scoped API endpoint with instance in URL
|
||||||
|
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s/utilities/dashboard/token", instanceName))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Process response
|
||||||
|
data := resp.GetMap("data")
|
||||||
|
if data == nil {
|
||||||
|
return fmt.Errorf("no data in response")
|
||||||
|
}
|
||||||
|
|
||||||
|
token, ok := data["token"].(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("no token in response")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Display result
|
||||||
|
fmt.Println(token)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Key Principles
|
||||||
|
|
||||||
|
1. **Get instance from context**: Use `getInstanceName()` to get the current instance from CLI context
|
||||||
|
2. **Instance in URL path**: Include the instance name in the API endpoint URL path
|
||||||
|
3. **Stateless API calls**: Don't rely on server-side session state - pass instance explicitly
|
||||||
|
4. **Handle errors gracefully**: Return clear error messages if instance is not set or API call fails
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ var operationGetCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/operations/%s?instance=%s", args[0], inst))
|
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s/operations/%s", inst, args[0]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,12 @@ var operationListCmd = &cobra.Command{
|
|||||||
Use: "list",
|
Use: "list",
|
||||||
Short: "List operations",
|
Short: "List operations",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
resp, err := apiClient.Get("/api/v1/operations")
|
inst, err := getInstanceName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s/operations", inst))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -90,7 +95,7 @@ func streamOperationOutput(opID string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Connect to SSE stream
|
// Connect to SSE stream
|
||||||
url := fmt.Sprintf("%s/api/v1/operations/%s/stream?instance=%s", baseURL, opID, inst)
|
url := fmt.Sprintf("%s/api/v1/instances/%s/operations/%s/stream", baseURL, inst, opID)
|
||||||
client := sse.NewClient(url)
|
client := sse.NewClient(url)
|
||||||
events := make(chan *sse.Event)
|
events := make(chan *sse.Event)
|
||||||
|
|
||||||
@@ -105,7 +110,7 @@ func streamOperationOutput(opID string) error {
|
|||||||
ticker := time.NewTicker(500 * time.Millisecond)
|
ticker := time.NewTicker(500 * time.Millisecond)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/operations/%s?instance=%s", opID, inst))
|
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s/operations/%s", inst, opID))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
status := resp.GetString("status")
|
status := resp.GetString("status")
|
||||||
if status == "completed" || status == "failed" {
|
if status == "completed" || status == "failed" {
|
||||||
|
|||||||
@@ -38,7 +38,11 @@ var dashboardTokenCmd = &cobra.Command{
|
|||||||
Use: "token",
|
Use: "token",
|
||||||
Short: "Get dashboard token",
|
Short: "Get dashboard token",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
resp, err := apiClient.Get("/api/v1/utilities/dashboard/token")
|
instanceName, err := getInstanceName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s/utilities/dashboard/token", instanceName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -68,7 +72,12 @@ var nodeIPCmd = &cobra.Command{
|
|||||||
Use: "node-ip",
|
Use: "node-ip",
|
||||||
Short: "Get control plane IP",
|
Short: "Get control plane IP",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
resp, err := apiClient.Get("/api/v1/utilities/controlplane/ip")
|
inst, err := getInstanceName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s/utilities/controlplane/ip", inst))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,16 @@ var versionCmd = &cobra.Command{
|
|||||||
|
|
||||||
// If connected to daemon, show cluster versions
|
// If connected to daemon, show cluster versions
|
||||||
if apiClient != nil {
|
if apiClient != nil {
|
||||||
resp, err := apiClient.Get("/api/v1/utilities/version")
|
inst, err := getInstanceName()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if k8s, ok := resp.Data["kubernetes"].(string); ok {
|
resp, err := apiClient.Get(fmt.Sprintf("/api/v1/instances/%s/utilities/version", inst))
|
||||||
fmt.Printf("Kubernetes: %s\n", k8s)
|
if err == nil {
|
||||||
}
|
if k8s, ok := resp.Data["kubernetes"].(string); ok {
|
||||||
if talos, ok := resp.Data["talos"].(string); ok && talos != "" {
|
fmt.Printf("Kubernetes: %s\n", k8s)
|
||||||
fmt.Printf("Talos: %s\n", talos)
|
}
|
||||||
|
if talos, ok := resp.Data["talos"].(string); ok && talos != "" {
|
||||||
|
fmt.Printf("Talos: %s\n", talos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user