mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 13:56:57 +00:00
220 lines
5.8 KiB
Go
220 lines
5.8 KiB
Go
package namespacecmd
|
|
|
|
import (
|
|
"bufio"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/DeBrosOfficial/network/pkg/auth"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var rqliteCmd = &cobra.Command{
|
|
Use: "rqlite",
|
|
Short: "Manage the namespace's internal RQLite database",
|
|
Long: "Export and import the namespace's internal RQLite database (stores deployments, DNS records, API keys, etc.).",
|
|
}
|
|
|
|
var rqliteExportCmd = &cobra.Command{
|
|
Use: "export",
|
|
Short: "Export the namespace's RQLite database to a local SQLite file",
|
|
Long: "Downloads a consistent SQLite snapshot of the namespace's internal RQLite database.",
|
|
RunE: rqliteExport,
|
|
}
|
|
|
|
var rqliteImportCmd = &cobra.Command{
|
|
Use: "import",
|
|
Short: "Import a SQLite dump into the namespace's RQLite (DESTRUCTIVE)",
|
|
Long: `Replaces the namespace's entire RQLite database with the contents of the provided SQLite file.
|
|
|
|
WARNING: This is a destructive operation. All existing data in the namespace's RQLite
|
|
(deployments, DNS records, API keys, etc.) will be replaced with the imported file.`,
|
|
RunE: rqliteImport,
|
|
}
|
|
|
|
func init() {
|
|
rqliteExportCmd.Flags().StringP("output", "o", "", "Output file path (default: rqlite-export.db)")
|
|
|
|
rqliteImportCmd.Flags().StringP("input", "i", "", "Input SQLite file path")
|
|
_ = rqliteImportCmd.MarkFlagRequired("input")
|
|
|
|
rqliteCmd.AddCommand(rqliteExportCmd)
|
|
rqliteCmd.AddCommand(rqliteImportCmd)
|
|
|
|
Cmd.AddCommand(rqliteCmd)
|
|
}
|
|
|
|
func rqliteExport(cmd *cobra.Command, args []string) error {
|
|
output, _ := cmd.Flags().GetString("output")
|
|
if output == "" {
|
|
output = "rqlite-export.db"
|
|
}
|
|
|
|
apiURL := nsRQLiteAPIURL()
|
|
token, err := nsRQLiteAuthToken()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
url := apiURL + "/v1/rqlite/export"
|
|
|
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create request: %w", err)
|
|
}
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{
|
|
Timeout: 0,
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
},
|
|
}
|
|
|
|
fmt.Printf("Exporting RQLite database to %s...\n", output)
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to connect to gateway: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return fmt.Errorf("export failed (HTTP %d): %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
outFile, err := os.Create(output)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create output file: %w", err)
|
|
}
|
|
defer outFile.Close()
|
|
|
|
written, err := io.Copy(outFile, resp.Body)
|
|
if err != nil {
|
|
os.Remove(output)
|
|
return fmt.Errorf("failed to write export file: %w", err)
|
|
}
|
|
|
|
fmt.Printf("Export complete: %s (%d bytes)\n", output, written)
|
|
return nil
|
|
}
|
|
|
|
func rqliteImport(cmd *cobra.Command, args []string) error {
|
|
input, _ := cmd.Flags().GetString("input")
|
|
|
|
info, err := os.Stat(input)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot access input file: %w", err)
|
|
}
|
|
if info.IsDir() {
|
|
return fmt.Errorf("input path is a directory, not a file")
|
|
}
|
|
|
|
store, err := auth.LoadEnhancedCredentials()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load credentials: %w", err)
|
|
}
|
|
gatewayURL := auth.GetDefaultGatewayURL()
|
|
creds := store.GetDefaultCredential(gatewayURL)
|
|
if creds == nil || !creds.IsValid() {
|
|
return fmt.Errorf("not authenticated. Run 'orama auth login' first")
|
|
}
|
|
|
|
namespace := creds.Namespace
|
|
if namespace == "" {
|
|
namespace = "default"
|
|
}
|
|
|
|
fmt.Printf("WARNING: This will REPLACE the entire RQLite database for namespace '%s'.\n", namespace)
|
|
fmt.Printf("All existing data (deployments, DNS records, API keys, etc.) will be lost.\n")
|
|
fmt.Printf("Importing from: %s (%d bytes)\n\n", input, info.Size())
|
|
fmt.Printf("Type the namespace name '%s' to confirm: ", namespace)
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
scanner.Scan()
|
|
confirmation := strings.TrimSpace(scanner.Text())
|
|
if confirmation != namespace {
|
|
return fmt.Errorf("aborted - namespace name did not match")
|
|
}
|
|
|
|
apiURL := nsRQLiteAPIURL()
|
|
token, err := nsRQLiteAuthToken()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
file, err := os.Open(input)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open input file: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
url := apiURL + "/v1/rqlite/import"
|
|
|
|
req, err := http.NewRequest(http.MethodPost, url, file)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create request: %w", err)
|
|
}
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/octet-stream")
|
|
req.ContentLength = info.Size()
|
|
|
|
client := &http.Client{
|
|
Timeout: 0,
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
},
|
|
}
|
|
|
|
fmt.Printf("Importing database...\n")
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to connect to gateway: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("import failed (HTTP %d): %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
fmt.Printf("Import complete. The namespace '%s' RQLite database has been replaced.\n", namespace)
|
|
return nil
|
|
}
|
|
|
|
func nsRQLiteAPIURL() string {
|
|
if url := os.Getenv("ORAMA_API_URL"); url != "" {
|
|
return url
|
|
}
|
|
return auth.GetDefaultGatewayURL()
|
|
}
|
|
|
|
func nsRQLiteAuthToken() (string, error) {
|
|
if token := os.Getenv("ORAMA_TOKEN"); token != "" {
|
|
return token, nil
|
|
}
|
|
|
|
store, err := auth.LoadEnhancedCredentials()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to load credentials: %w", err)
|
|
}
|
|
|
|
gatewayURL := auth.GetDefaultGatewayURL()
|
|
creds := store.GetDefaultCredential(gatewayURL)
|
|
if creds == nil {
|
|
return "", fmt.Errorf("no credentials found for %s. Run 'orama auth login' to authenticate", gatewayURL)
|
|
}
|
|
|
|
if !creds.IsValid() {
|
|
return "", fmt.Errorf("credentials expired for %s. Run 'orama auth login' to re-authenticate", gatewayURL)
|
|
}
|
|
|
|
return creds.APIKey, nil
|
|
}
|