mirror of
https://github.com/juanfont/headscale.git
synced 2025-08-10 13:46:46 +02:00
integration/hsic: extract artifacts as directories instead of tar files
- Change SaveProfile to extract to hostname-pprof/ directory - Change SaveMapResponses to extract to hostname-mapresponses/ directory - Change SaveDatabase to extract .db file directly (not as tar) - Add extractTarToDirectory helper function for tar extraction - This makes test artifacts directly browsable without manual extraction
This commit is contained in:
parent
4205d3c1b0
commit
e822877215
@ -1,6 +1,8 @@
|
||||
package hsic
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"cmp"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
@ -12,6 +14,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -561,22 +564,67 @@ func (t *HeadscaleInContainer) SaveMetrics(savePath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractTarToDirectory extracts a tar archive to a directory.
|
||||
func extractTarToDirectory(tarData []byte, targetDir string) error {
|
||||
if err := os.MkdirAll(targetDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create directory %s: %w", targetDir, err)
|
||||
}
|
||||
|
||||
tarReader := tar.NewReader(bytes.NewReader(tarData))
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read tar header: %w", err)
|
||||
}
|
||||
|
||||
// Clean the path to prevent directory traversal
|
||||
cleanName := filepath.Clean(header.Name)
|
||||
if strings.Contains(cleanName, "..") {
|
||||
continue // Skip potentially dangerous paths
|
||||
}
|
||||
|
||||
targetPath := filepath.Join(targetDir, filepath.Base(cleanName))
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
// Create directory
|
||||
if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil {
|
||||
return fmt.Errorf("failed to create directory %s: %w", targetPath, err)
|
||||
}
|
||||
case tar.TypeReg:
|
||||
// Create file
|
||||
outFile, err := os.Create(targetPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create file %s: %w", targetPath, err)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||
outFile.Close()
|
||||
return fmt.Errorf("failed to copy file contents: %w", err)
|
||||
}
|
||||
outFile.Close()
|
||||
|
||||
// Set file permissions
|
||||
if err := os.Chmod(targetPath, os.FileMode(header.Mode)); err != nil {
|
||||
return fmt.Errorf("failed to set file permissions: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *HeadscaleInContainer) SaveProfile(savePath string) error {
|
||||
tarFile, err := t.FetchPath("/tmp/profile")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(
|
||||
path.Join(savePath, t.hostname+".pprof.tar"),
|
||||
tarFile,
|
||||
os.ModePerm,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
targetDir := path.Join(savePath, t.hostname+"-pprof")
|
||||
return extractTarToDirectory(tarFile, targetDir)
|
||||
}
|
||||
|
||||
func (t *HeadscaleInContainer) SaveMapResponses(savePath string) error {
|
||||
@ -585,16 +633,8 @@ func (t *HeadscaleInContainer) SaveMapResponses(savePath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(
|
||||
path.Join(savePath, t.hostname+".maps.tar"),
|
||||
tarFile,
|
||||
os.ModePerm,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
targetDir := path.Join(savePath, t.hostname+"-mapresponses")
|
||||
return extractTarToDirectory(tarFile, targetDir)
|
||||
}
|
||||
|
||||
func (t *HeadscaleInContainer) SaveDatabase(savePath string) error {
|
||||
@ -603,16 +643,35 @@ func (t *HeadscaleInContainer) SaveDatabase(savePath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(
|
||||
path.Join(savePath, t.hostname+".db.tar"),
|
||||
tarFile,
|
||||
os.ModePerm,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
// For database, extract the single SQLite file directly
|
||||
tarReader := tar.NewReader(bytes.NewReader(tarFile))
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read tar header: %w", err)
|
||||
}
|
||||
|
||||
if header.Typeflag == tar.TypeReg && strings.Contains(header.Name, ".sqlite") {
|
||||
dbPath := path.Join(savePath, t.hostname+".db")
|
||||
outFile, err := os.Create(dbPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create database file: %w", err)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||
outFile.Close()
|
||||
return fmt.Errorf("failed to copy database file: %w", err)
|
||||
}
|
||||
outFile.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return fmt.Errorf("database file not found in tar archive")
|
||||
}
|
||||
|
||||
// Execute runs a command inside the Headscale container and returns the
|
||||
|
Loading…
Reference in New Issue
Block a user