Instance-namespace additional utility endpoints.
This commit is contained in:
@@ -89,9 +89,19 @@ func (api *API) UtilitiesDashboardToken(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Using Kubeconfig with kubectl/talosctl
|
#### Key Principles
|
||||||
|
|
||||||
When making kubectl or talosctl calls for a specific instance, use the `tools.WithKubeconfig()` helper to set the KUBECONFIG environment variable:
|
1. **Instance name in URL**: Always include instance name as a path parameter (`{name}`)
|
||||||
|
2. **Extract from mux.Vars()**: Get instance name from `mux.Vars(r)["name"]`, not from context
|
||||||
|
3. **Validate instance**: Always validate the instance exists before operations
|
||||||
|
4. **Use path helpers**: Use `tools.GetKubeconfigPath()`, `tools.GetInstanceConfigPath()`, etc. instead of inline `filepath.Join()` constructions
|
||||||
|
5. **Stateless handlers**: Handlers should not depend on session state or current context
|
||||||
|
|
||||||
|
### kubectl and talosctl Commands
|
||||||
|
|
||||||
|
When making kubectl or talosctl calls for a specific instance, always use the `tools` package helpers to set the correct context.
|
||||||
|
|
||||||
|
#### Using kubectl with Instance Kubeconfig
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// In utilities.go or similar
|
// In utilities.go or similar
|
||||||
@@ -108,11 +118,25 @@ func GetDashboardToken(kubeconfigPath string) (*DashboardToken, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Using talosctl with Instance Talosconfig
|
||||||
|
|
||||||
|
```go
|
||||||
|
// In cluster operations
|
||||||
|
func GetClusterHealth(talosconfigPath string, nodeIP string) error {
|
||||||
|
cmd := exec.Command("talosctl", "health", "--nodes", nodeIP)
|
||||||
|
tools.WithTalosconfig(cmd, talosconfigPath)
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to check health: %w", err)
|
||||||
|
}
|
||||||
|
// Process output...
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### Key Principles
|
#### Key Principles
|
||||||
|
|
||||||
1. **Instance name in URL**: Always include instance name as a path parameter (`{name}`)
|
1. **Use tools helpers**: Always use `tools.WithKubeconfig()` or `tools.WithTalosconfig()` instead of manually setting environment variables
|
||||||
2. **Extract from mux.Vars()**: Get instance name from `mux.Vars(r)["name"]`, not from context
|
2. **Get paths from tools package**: Use `tools.GetKubeconfigPath()` or `tools.GetTalosconfigPath()` to construct config paths
|
||||||
3. **Validate instance**: Always validate the instance exists before operations
|
3. **One config per command**: Each exec.Command should have its config set via the appropriate helper
|
||||||
4. **Use path helpers**: Use `tools.GetKubeconfigPath()`, `tools.GetInstanceConfigPath()`, etc. instead of inline `filepath.Join()` constructions
|
4. **Error handling**: Always check for command execution errors and provide context
|
||||||
5. **Stateless handlers**: Handlers should not depend on session state or current context
|
|
||||||
6. **Use tools helpers**: Use `tools.WithKubeconfig()` for kubectl/talosctl commands
|
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ func (api *API) RegisterRoutes(r *mux.Router) {
|
|||||||
|
|
||||||
// Operations
|
// Operations
|
||||||
r.HandleFunc("/api/v1/instances/{name}/operations", api.OperationList).Methods("GET")
|
r.HandleFunc("/api/v1/instances/{name}/operations", api.OperationList).Methods("GET")
|
||||||
r.HandleFunc("/api/v1/operations/{id}", api.OperationGet).Methods("GET")
|
r.HandleFunc("/api/v1/instances/{name}/operations/{id}", api.OperationGet).Methods("GET")
|
||||||
r.HandleFunc("/api/v1/operations/{id}/stream", api.OperationStream).Methods("GET")
|
r.HandleFunc("/api/v1/instances/{name}/operations/{id}/stream", api.OperationStream).Methods("GET")
|
||||||
r.HandleFunc("/api/v1/operations/{id}/cancel", api.OperationCancel).Methods("POST")
|
r.HandleFunc("/api/v1/instances/{name}/operations/{id}/cancel", api.OperationCancel).Methods("POST")
|
||||||
|
|
||||||
// Cluster operations
|
// Cluster operations
|
||||||
r.HandleFunc("/api/v1/instances/{name}/cluster/config/generate", api.ClusterGenerateConfig).Methods("POST")
|
r.HandleFunc("/api/v1/instances/{name}/cluster/config/generate", api.ClusterGenerateConfig).Methods("POST")
|
||||||
@@ -156,13 +156,12 @@ func (api *API) RegisterRoutes(r *mux.Router) {
|
|||||||
r.HandleFunc("/api/v1/instances/{name}/apps/{app}/restore", api.BackupAppRestore).Methods("POST")
|
r.HandleFunc("/api/v1/instances/{name}/apps/{app}/restore", api.BackupAppRestore).Methods("POST")
|
||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
r.HandleFunc("/api/v1/utilities/health", api.UtilitiesHealth).Methods("GET")
|
|
||||||
r.HandleFunc("/api/v1/instances/{name}/utilities/health", api.InstanceUtilitiesHealth).Methods("GET")
|
r.HandleFunc("/api/v1/instances/{name}/utilities/health", api.InstanceUtilitiesHealth).Methods("GET")
|
||||||
r.HandleFunc("/api/v1/instances/{name}/utilities/dashboard/token", api.UtilitiesDashboardToken).Methods("GET")
|
r.HandleFunc("/api/v1/instances/{name}/utilities/dashboard/token", api.UtilitiesDashboardToken).Methods("GET")
|
||||||
r.HandleFunc("/api/v1/utilities/nodes/ips", api.UtilitiesNodeIPs).Methods("GET")
|
r.HandleFunc("/api/v1/instances/{name}/utilities/nodes/ips", api.UtilitiesNodeIPs).Methods("GET")
|
||||||
r.HandleFunc("/api/v1/utilities/controlplane/ip", api.UtilitiesControlPlaneIP).Methods("GET")
|
r.HandleFunc("/api/v1/instances/{name}/utilities/controlplane/ip", api.UtilitiesControlPlaneIP).Methods("GET")
|
||||||
r.HandleFunc("/api/v1/utilities/secrets/{secret}/copy", api.UtilitiesSecretCopy).Methods("POST")
|
r.HandleFunc("/api/v1/instances/{name}/utilities/secrets/{secret}/copy", api.UtilitiesSecretCopy).Methods("POST")
|
||||||
r.HandleFunc("/api/v1/utilities/version", api.UtilitiesVersion).Methods("GET")
|
r.HandleFunc("/api/v1/instances/{name}/utilities/version", api.UtilitiesVersion).Methods("GET")
|
||||||
|
|
||||||
// dnsmasq management
|
// dnsmasq management
|
||||||
r.HandleFunc("/api/v1/dnsmasq/status", api.DnsmasqStatus).Methods("GET")
|
r.HandleFunc("/api/v1/dnsmasq/status", api.DnsmasqStatus).Methods("GET")
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ import (
|
|||||||
// OperationGet returns operation status
|
// OperationGet returns operation status
|
||||||
func (api *API) OperationGet(w http.ResponseWriter, r *http.Request) {
|
func (api *API) OperationGet(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
instanceName := vars["name"]
|
||||||
opID := vars["id"]
|
opID := vars["id"]
|
||||||
|
|
||||||
// Extract instance name from query param or header
|
// Validate instance exists
|
||||||
instanceName := r.URL.Query().Get("instance")
|
if err := api.instance.ValidateInstance(instanceName); err != nil {
|
||||||
if instanceName == "" {
|
respondError(w, http.StatusNotFound, fmt.Sprintf("Instance not found: %v", err))
|
||||||
respondError(w, http.StatusBadRequest, "instance parameter is required")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,12 +64,12 @@ func (api *API) OperationList(w http.ResponseWriter, r *http.Request) {
|
|||||||
// OperationCancel cancels an operation
|
// OperationCancel cancels an operation
|
||||||
func (api *API) OperationCancel(w http.ResponseWriter, r *http.Request) {
|
func (api *API) OperationCancel(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
instanceName := vars["name"]
|
||||||
opID := vars["id"]
|
opID := vars["id"]
|
||||||
|
|
||||||
// Extract instance name from query param
|
// Validate instance exists
|
||||||
instanceName := r.URL.Query().Get("instance")
|
if err := api.instance.ValidateInstance(instanceName); err != nil {
|
||||||
if instanceName == "" {
|
respondError(w, http.StatusNotFound, fmt.Sprintf("Instance not found: %v", err))
|
||||||
respondError(w, http.StatusBadRequest, "instance parameter is required")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,12 +89,12 @@ func (api *API) OperationCancel(w http.ResponseWriter, r *http.Request) {
|
|||||||
// OperationStream streams operation output via Server-Sent Events (SSE)
|
// OperationStream streams operation output via Server-Sent Events (SSE)
|
||||||
func (api *API) OperationStream(w http.ResponseWriter, r *http.Request) {
|
func (api *API) OperationStream(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
instanceName := vars["name"]
|
||||||
opID := vars["id"]
|
opID := vars["id"]
|
||||||
|
|
||||||
// Extract instance name from query param
|
// Validate instance exists
|
||||||
instanceName := r.URL.Query().Get("instance")
|
if err := api.instance.ValidateInstance(instanceName); err != nil {
|
||||||
if instanceName == "" {
|
respondError(w, http.StatusNotFound, fmt.Sprintf("Instance not found: %v", err))
|
||||||
respondError(w, http.StatusBadRequest, "instance parameter is required")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,20 +10,6 @@ import (
|
|||||||
"github.com/wild-cloud/wild-central/daemon/internal/utilities"
|
"github.com/wild-cloud/wild-central/daemon/internal/utilities"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UtilitiesHealth returns cluster health status (legacy, no instance context)
|
|
||||||
func (api *API) UtilitiesHealth(w http.ResponseWriter, r *http.Request) {
|
|
||||||
status, err := utilities.GetClusterHealth("")
|
|
||||||
if err != nil {
|
|
||||||
respondError(w, http.StatusInternalServerError, "Failed to get cluster health")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
respondJSON(w, http.StatusOK, map[string]interface{}{
|
|
||||||
"success": true,
|
|
||||||
"data": status,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceUtilitiesHealth returns cluster health status for a specific instance
|
// InstanceUtilitiesHealth returns cluster health status for a specific instance
|
||||||
func (api *API) InstanceUtilitiesHealth(w http.ResponseWriter, r *http.Request) {
|
func (api *API) InstanceUtilitiesHealth(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
@@ -82,7 +68,19 @@ func (api *API) UtilitiesDashboardToken(w http.ResponseWriter, r *http.Request)
|
|||||||
|
|
||||||
// UtilitiesNodeIPs returns IP addresses for all cluster nodes
|
// UtilitiesNodeIPs returns IP addresses for all cluster nodes
|
||||||
func (api *API) UtilitiesNodeIPs(w http.ResponseWriter, r *http.Request) {
|
func (api *API) UtilitiesNodeIPs(w http.ResponseWriter, r *http.Request) {
|
||||||
nodes, err := utilities.GetNodeIPs()
|
vars := mux.Vars(r)
|
||||||
|
instanceName := vars["name"]
|
||||||
|
|
||||||
|
// Validate instance exists
|
||||||
|
if err := api.instance.ValidateInstance(instanceName); err != nil {
|
||||||
|
respondError(w, http.StatusNotFound, fmt.Sprintf("Instance not found: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get kubeconfig path for this instance
|
||||||
|
kubeconfigPath := tools.GetKubeconfigPath(api.dataDir, instanceName)
|
||||||
|
|
||||||
|
nodes, err := utilities.GetNodeIPs(kubeconfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondError(w, http.StatusInternalServerError, "Failed to get node IPs")
|
respondError(w, http.StatusInternalServerError, "Failed to get node IPs")
|
||||||
return
|
return
|
||||||
@@ -98,7 +96,19 @@ func (api *API) UtilitiesNodeIPs(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// UtilitiesControlPlaneIP returns the control plane IP
|
// UtilitiesControlPlaneIP returns the control plane IP
|
||||||
func (api *API) UtilitiesControlPlaneIP(w http.ResponseWriter, r *http.Request) {
|
func (api *API) UtilitiesControlPlaneIP(w http.ResponseWriter, r *http.Request) {
|
||||||
ip, err := utilities.GetControlPlaneIP()
|
vars := mux.Vars(r)
|
||||||
|
instanceName := vars["name"]
|
||||||
|
|
||||||
|
// Validate instance exists
|
||||||
|
if err := api.instance.ValidateInstance(instanceName); err != nil {
|
||||||
|
respondError(w, http.StatusNotFound, fmt.Sprintf("Instance not found: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get kubeconfig path for this instance
|
||||||
|
kubeconfigPath := tools.GetKubeconfigPath(api.dataDir, instanceName)
|
||||||
|
|
||||||
|
ip, err := utilities.GetControlPlaneIP(kubeconfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondError(w, http.StatusInternalServerError, "Failed to get control plane IP")
|
respondError(w, http.StatusInternalServerError, "Failed to get control plane IP")
|
||||||
return
|
return
|
||||||
@@ -115,8 +125,15 @@ func (api *API) UtilitiesControlPlaneIP(w http.ResponseWriter, r *http.Request)
|
|||||||
// UtilitiesSecretCopy copies a secret between namespaces
|
// UtilitiesSecretCopy copies a secret between namespaces
|
||||||
func (api *API) UtilitiesSecretCopy(w http.ResponseWriter, r *http.Request) {
|
func (api *API) UtilitiesSecretCopy(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
instanceName := vars["name"]
|
||||||
secretName := vars["secret"]
|
secretName := vars["secret"]
|
||||||
|
|
||||||
|
// Validate instance exists
|
||||||
|
if err := api.instance.ValidateInstance(instanceName); err != nil {
|
||||||
|
respondError(w, http.StatusNotFound, fmt.Sprintf("Instance not found: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var req struct {
|
var req struct {
|
||||||
SourceNamespace string `json:"source_namespace"`
|
SourceNamespace string `json:"source_namespace"`
|
||||||
DestinationNamespace string `json:"destination_namespace"`
|
DestinationNamespace string `json:"destination_namespace"`
|
||||||
@@ -132,7 +149,10 @@ func (api *API) UtilitiesSecretCopy(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := utilities.CopySecretBetweenNamespaces(secretName, req.SourceNamespace, req.DestinationNamespace); err != nil {
|
// Get kubeconfig path for this instance
|
||||||
|
kubeconfigPath := tools.GetKubeconfigPath(api.dataDir, instanceName)
|
||||||
|
|
||||||
|
if err := utilities.CopySecretBetweenNamespaces(kubeconfigPath, secretName, req.SourceNamespace, req.DestinationNamespace); err != nil {
|
||||||
respondError(w, http.StatusInternalServerError, "Failed to copy secret")
|
respondError(w, http.StatusInternalServerError, "Failed to copy secret")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -145,7 +165,19 @@ func (api *API) UtilitiesSecretCopy(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// UtilitiesVersion returns cluster and Talos versions
|
// UtilitiesVersion returns cluster and Talos versions
|
||||||
func (api *API) UtilitiesVersion(w http.ResponseWriter, r *http.Request) {
|
func (api *API) UtilitiesVersion(w http.ResponseWriter, r *http.Request) {
|
||||||
k8sVersion, err := utilities.GetClusterVersion()
|
vars := mux.Vars(r)
|
||||||
|
instanceName := vars["name"]
|
||||||
|
|
||||||
|
// Validate instance exists
|
||||||
|
if err := api.instance.ValidateInstance(instanceName); err != nil {
|
||||||
|
respondError(w, http.StatusNotFound, fmt.Sprintf("Instance not found: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get kubeconfig path for this instance
|
||||||
|
kubeconfigPath := tools.GetKubeconfigPath(api.dataDir, instanceName)
|
||||||
|
|
||||||
|
k8sVersion, err := utilities.GetClusterVersion(kubeconfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondError(w, http.StatusInternalServerError, "Failed to get cluster version")
|
respondError(w, http.StatusInternalServerError, "Failed to get cluster version")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -273,7 +273,8 @@ func (m *Manager) GetStatus(instanceName string) (*ClusterStatus, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get node count and types using kubectl
|
// Get node count and types using kubectl
|
||||||
cmd := exec.Command("kubectl", "--kubeconfig", kubeconfigPath, "get", "nodes", "-o", "json")
|
cmd := exec.Command("kubectl", "get", "nodes", "-o", "json")
|
||||||
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
status.Status = "unreachable"
|
status.Status = "unreachable"
|
||||||
@@ -356,9 +357,9 @@ func (m *Manager) GetStatus(instanceName string) (*ClusterStatus, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, svc := range services {
|
for _, svc := range services {
|
||||||
cmd := exec.Command("kubectl", "--kubeconfig", kubeconfigPath,
|
cmd := exec.Command("kubectl", "get", "pods", "-n", svc.namespace, "-l", svc.selector,
|
||||||
"get", "pods", "-n", svc.namespace, "-l", svc.selector,
|
|
||||||
"-o", "jsonpath={.items[*].status.phase}")
|
"-o", "jsonpath={.items[*].status.phase}")
|
||||||
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil || len(output) == 0 {
|
if err != nil || len(output) == 0 {
|
||||||
status.Services[svc.name] = "not_found"
|
status.Services[svc.name] = "not_found"
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ func (m *Manager) checkServiceStatus(instanceName, serviceName string) string {
|
|||||||
|
|
||||||
// Special case: NFS doesn't have a deployment, check for StorageClass instead
|
// Special case: NFS doesn't have a deployment, check for StorageClass instead
|
||||||
if serviceName == "nfs" {
|
if serviceName == "nfs" {
|
||||||
cmd := exec.Command("kubectl", "--kubeconfig", kubeconfigPath, "get", "storageclass", "nfs", "-o", "name")
|
cmd := exec.Command("kubectl", "get", "storageclass", "nfs", "-o", "name")
|
||||||
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
if err := cmd.Run(); err == nil {
|
if err := cmd.Run(); err == nil {
|
||||||
return "deployed"
|
return "deployed"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,12 +84,8 @@ func GetClusterHealth(kubeconfigPath string) (*HealthStatus, error) {
|
|||||||
|
|
||||||
// checkComponent checks if a component is running
|
// checkComponent checks if a component is running
|
||||||
func checkComponent(kubeconfigPath, namespace, selector string) error {
|
func checkComponent(kubeconfigPath, namespace, selector string) error {
|
||||||
args := []string{"get", "pods", "-n", namespace, "-l", selector, "-o", "json"}
|
cmd := exec.Command("kubectl", "get", "pods", "-n", namespace, "-l", selector, "-o", "json")
|
||||||
if kubeconfigPath != "" {
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
args = append([]string{"--kubeconfig", kubeconfigPath}, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("kubectl", args...)
|
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get pods: %w", err)
|
return fmt.Errorf("failed to get pods: %w", err)
|
||||||
@@ -172,8 +168,9 @@ func GetDashboardTokenFromSecret(kubeconfigPath string) (*DashboardToken, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetNodeIPs returns IP addresses for all cluster nodes
|
// GetNodeIPs returns IP addresses for all cluster nodes
|
||||||
func GetNodeIPs() ([]*NodeIP, error) {
|
func GetNodeIPs(kubeconfigPath string) ([]*NodeIP, error) {
|
||||||
cmd := exec.Command("kubectl", "get", "nodes", "-o", "json")
|
cmd := exec.Command("kubectl", "get", "nodes", "-o", "json")
|
||||||
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get nodes: %w", err)
|
return nil, fmt.Errorf("failed to get nodes: %w", err)
|
||||||
@@ -217,9 +214,10 @@ func GetNodeIPs() ([]*NodeIP, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetControlPlaneIP returns the IP of the first control plane node
|
// GetControlPlaneIP returns the IP of the first control plane node
|
||||||
func GetControlPlaneIP() (string, error) {
|
func GetControlPlaneIP(kubeconfigPath string) (string, error) {
|
||||||
cmd := exec.Command("kubectl", "get", "nodes", "-l", "node-role.kubernetes.io/control-plane",
|
cmd := exec.Command("kubectl", "get", "nodes", "-l", "node-role.kubernetes.io/control-plane",
|
||||||
"-o", "jsonpath={.items[0].status.addresses[?(@.type==\"InternalIP\")].address}")
|
"-o", "jsonpath={.items[0].status.addresses[?(@.type==\"InternalIP\")].address}")
|
||||||
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get control plane IP: %w", err)
|
return "", fmt.Errorf("failed to get control plane IP: %w", err)
|
||||||
@@ -234,9 +232,10 @@ func GetControlPlaneIP() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CopySecretBetweenNamespaces copies a secret from one namespace to another
|
// CopySecretBetweenNamespaces copies a secret from one namespace to another
|
||||||
func CopySecretBetweenNamespaces(secretName, srcNamespace, dstNamespace string) error {
|
func CopySecretBetweenNamespaces(kubeconfigPath, secretName, srcNamespace, dstNamespace string) error {
|
||||||
// Get secret from source namespace
|
// Get secret from source namespace
|
||||||
cmd := exec.Command("kubectl", "get", "secret", "-n", srcNamespace, secretName, "-o", "json")
|
cmd := exec.Command("kubectl", "get", "secret", "-n", srcNamespace, secretName, "-o", "json")
|
||||||
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get secret from %s: %w", srcNamespace, err)
|
return fmt.Errorf("failed to get secret from %s: %w", srcNamespace, err)
|
||||||
@@ -264,6 +263,7 @@ func CopySecretBetweenNamespaces(secretName, srcNamespace, dstNamespace string)
|
|||||||
|
|
||||||
// Apply to destination namespace
|
// Apply to destination namespace
|
||||||
cmd = exec.Command("kubectl", "apply", "-f", "-")
|
cmd = exec.Command("kubectl", "apply", "-f", "-")
|
||||||
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
cmd.Stdin = strings.NewReader(string(secretJSON))
|
cmd.Stdin = strings.NewReader(string(secretJSON))
|
||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
return fmt.Errorf("failed to apply secret to %s: %w\nOutput: %s", dstNamespace, err, string(output))
|
return fmt.Errorf("failed to apply secret to %s: %w\nOutput: %s", dstNamespace, err, string(output))
|
||||||
@@ -273,8 +273,9 @@ func CopySecretBetweenNamespaces(secretName, srcNamespace, dstNamespace string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetClusterVersion returns the Kubernetes cluster version
|
// GetClusterVersion returns the Kubernetes cluster version
|
||||||
func GetClusterVersion() (string, error) {
|
func GetClusterVersion(kubeconfigPath string) (string, error) {
|
||||||
cmd := exec.Command("kubectl", "version", "-o", "json")
|
cmd := exec.Command("kubectl", "version", "-o", "json")
|
||||||
|
tools.WithKubeconfig(cmd, kubeconfigPath)
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get cluster version: %w", err)
|
return "", fmt.Errorf("failed to get cluster version: %w", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user