Add raw export reanalyze flow for Redfish snapshots
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
@@ -70,15 +71,33 @@ func (s *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
)
|
||||
|
||||
if looksLikeJSONSnapshot(header.Filename, payload) {
|
||||
snapshotResult, snapshotErr := parseUploadedSnapshot(payload)
|
||||
if snapshotErr != nil {
|
||||
jsonError(w, "Failed to parse snapshot: "+snapshotErr.Error(), http.StatusBadRequest)
|
||||
if rawPkg, ok, err := parseRawExportPackage(payload); err != nil {
|
||||
jsonError(w, "Failed to parse raw export package: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
result = snapshotResult
|
||||
vendor = strings.TrimSpace(snapshotResult.Protocol)
|
||||
if vendor == "" {
|
||||
vendor = "snapshot"
|
||||
} else if ok {
|
||||
replayed, replayVendor, replayErr := s.reanalyzeRawExportPackage(rawPkg)
|
||||
if replayErr != nil {
|
||||
jsonError(w, "Failed to reanalyze raw export package: "+replayErr.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
result = replayed
|
||||
vendor = replayVendor
|
||||
if strings.TrimSpace(vendor) == "" {
|
||||
vendor = "snapshot"
|
||||
}
|
||||
s.SetRawExport(rawPkg)
|
||||
} else {
|
||||
snapshotResult, snapshotErr := parseUploadedSnapshot(payload)
|
||||
if snapshotErr != nil {
|
||||
jsonError(w, "Failed to parse snapshot: "+snapshotErr.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
result = snapshotResult
|
||||
vendor = strings.TrimSpace(snapshotResult.Protocol)
|
||||
if vendor == "" {
|
||||
vendor = "snapshot"
|
||||
}
|
||||
s.SetRawExport(newRawExportFromUploadedFile(header.Filename, header.Header.Get("Content-Type"), payload, result))
|
||||
}
|
||||
} else {
|
||||
// Parse archive
|
||||
@@ -90,6 +109,7 @@ func (s *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
result = p.Result()
|
||||
applyArchiveSourceMetadata(result)
|
||||
vendor = p.DetectedVendor()
|
||||
s.SetRawExport(newRawExportFromUploadedFile(header.Filename, header.Header.Get("Content-Type"), payload, result))
|
||||
}
|
||||
|
||||
s.SetResult(result)
|
||||
@@ -108,6 +128,77 @@ func (s *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) reanalyzeRawExportPackage(pkg *RawExportPackage) (*models.AnalysisResult, string, error) {
|
||||
if pkg == nil {
|
||||
return nil, "", fmt.Errorf("empty package")
|
||||
}
|
||||
switch pkg.Source.Kind {
|
||||
case "file_bytes":
|
||||
if strings.TrimSpace(pkg.Source.Encoding) != "base64" {
|
||||
return nil, "", fmt.Errorf("unsupported file_bytes encoding: %s", pkg.Source.Encoding)
|
||||
}
|
||||
data, err := base64.StdEncoding.DecodeString(pkg.Source.Data)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("decode source.data: %w", err)
|
||||
}
|
||||
return s.parseUploadedPayload(pkg.Source.Filename, data)
|
||||
case "live_redfish":
|
||||
if !strings.EqualFold(strings.TrimSpace(pkg.Source.Protocol), "redfish") {
|
||||
return nil, "", fmt.Errorf("unsupported live protocol: %s", pkg.Source.Protocol)
|
||||
}
|
||||
result, err := collector.ReplayRedfishFromRawPayloads(pkg.Source.RawPayloads, nil)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if result != nil {
|
||||
if strings.TrimSpace(result.Protocol) == "" {
|
||||
result.Protocol = "redfish"
|
||||
}
|
||||
if strings.TrimSpace(result.SourceType) == "" {
|
||||
result.SourceType = models.SourceTypeAPI
|
||||
}
|
||||
if strings.TrimSpace(result.TargetHost) == "" {
|
||||
result.TargetHost = strings.TrimSpace(pkg.Source.TargetHost)
|
||||
}
|
||||
if result.CollectedAt.IsZero() {
|
||||
result.CollectedAt = time.Now().UTC()
|
||||
}
|
||||
if strings.TrimSpace(result.Filename) == "" {
|
||||
target := result.TargetHost
|
||||
if target == "" {
|
||||
target = "snapshot"
|
||||
}
|
||||
result.Filename = "redfish://" + target
|
||||
}
|
||||
}
|
||||
return result, "redfish", nil
|
||||
default:
|
||||
return nil, "", fmt.Errorf("unsupported raw export source kind: %s", pkg.Source.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) parseUploadedPayload(filename string, payload []byte) (*models.AnalysisResult, string, error) {
|
||||
if looksLikeJSONSnapshot(filename, payload) {
|
||||
snapshotResult, err := parseUploadedSnapshot(payload)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
vendor := strings.TrimSpace(snapshotResult.Protocol)
|
||||
if vendor == "" {
|
||||
vendor = "snapshot"
|
||||
}
|
||||
return snapshotResult, vendor, nil
|
||||
}
|
||||
|
||||
p := parser.NewBMCParser()
|
||||
if err := p.ParseFromReader(bytes.NewReader(payload), filename); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
result := p.Result()
|
||||
applyArchiveSourceMetadata(result)
|
||||
return result, p.DetectedVendor(), nil
|
||||
}
|
||||
|
||||
func (s *Server) handleGetParsers(w http.ResponseWriter, r *http.Request) {
|
||||
jsonResponse(w, map[string]interface{}{
|
||||
"parsers": parser.ListParsersInfo(),
|
||||
@@ -667,8 +758,19 @@ func (s *Server) handleExportJSON(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", exportFilename(result, "json")))
|
||||
|
||||
if rawPkg := s.GetRawExport(); rawPkg != nil {
|
||||
rawPkg.ExportedAt = time.Now().UTC()
|
||||
rawPkg.Analysis = nil
|
||||
encoder := json.NewEncoder(w)
|
||||
encoder.SetIndent("", " ")
|
||||
if err := encoder.Encode(rawPkg); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
exp := exporter.New(result)
|
||||
exp.ExportJSON(w)
|
||||
_ = exp.ExportJSON(w)
|
||||
}
|
||||
|
||||
func (s *Server) handleExportReanimator(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -702,6 +804,7 @@ func (s *Server) handleExportReanimator(w http.ResponseWriter, r *http.Request)
|
||||
func (s *Server) handleClear(w http.ResponseWriter, r *http.Request) {
|
||||
s.SetResult(nil)
|
||||
s.SetDetectedVendor("")
|
||||
s.SetRawExport(nil)
|
||||
jsonResponse(w, map[string]string{
|
||||
"status": "ok",
|
||||
"message": "Data cleared",
|
||||
@@ -827,6 +930,9 @@ func (s *Server) startCollectionJob(jobID string, req CollectRequest) {
|
||||
s.jobManager.AppendJobLog(jobID, "Сбор завершен")
|
||||
s.SetResult(result)
|
||||
s.SetDetectedVendor(req.Protocol)
|
||||
if job, ok := s.jobManager.GetJob(jobID); ok {
|
||||
s.SetRawExport(newRawExportFromLiveCollect(result, req, job.Logs))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user