feat: delete firmware
This commit is contained in:
@@ -201,6 +201,60 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
delete:
|
||||||
|
summary: Delete firmware binary
|
||||||
|
description: |
|
||||||
|
Delete the firmware binary and metadata for the specified name and version.
|
||||||
|
This action cannot be undone.
|
||||||
|
operationId: deleteFirmware
|
||||||
|
parameters:
|
||||||
|
- name: name
|
||||||
|
in: path
|
||||||
|
description: Firmware name
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: "base"
|
||||||
|
- name: version
|
||||||
|
in: path
|
||||||
|
description: Firmware version (semantic versioning)
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: "1.0.0"
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Firmware deleted successfully
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
success:
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
example: "Firmware deleted successfully"
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: "base"
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
example: "1.0.0"
|
||||||
|
'404':
|
||||||
|
description: Firmware not found
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
'500':
|
||||||
|
description: Internal server error
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
|
||||||
/health:
|
/health:
|
||||||
get:
|
get:
|
||||||
summary: Health check
|
summary: Health check
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ func (a *App) SetupRoutes() *http.ServeMux {
|
|||||||
mux.HandleFunc("PUT /firmware/{name}/{version}", a.handler.UpdateFirmwareMetadata)
|
mux.HandleFunc("PUT /firmware/{name}/{version}", a.handler.UpdateFirmwareMetadata)
|
||||||
mux.HandleFunc("GET /firmware", a.handler.ListFirmware)
|
mux.HandleFunc("GET /firmware", a.handler.ListFirmware)
|
||||||
mux.HandleFunc("GET /firmware/{name}/{version}", a.handler.DownloadFirmware)
|
mux.HandleFunc("GET /firmware/{name}/{version}", a.handler.DownloadFirmware)
|
||||||
|
mux.HandleFunc("DELETE /firmware/{name}/{version}", a.handler.DeleteFirmware)
|
||||||
|
|
||||||
// Health check endpoint
|
// Health check endpoint
|
||||||
mux.HandleFunc("GET /health", a.handler.HealthCheck)
|
mux.HandleFunc("GET /health", a.handler.HealthCheck)
|
||||||
|
|||||||
@@ -199,6 +199,52 @@ func (h *FirmwareHandler) DownloadFirmware(w http.ResponseWriter, r *http.Reques
|
|||||||
http.ServeFile(w, r, filePath)
|
http.ServeFile(w, r, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteFirmware handles DELETE /firmware/{name}/{version} endpoint
|
||||||
|
func (h *FirmwareHandler) DeleteFirmware(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodDelete {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract path parameters
|
||||||
|
path := strings.TrimPrefix(r.URL.Path, "/firmware/")
|
||||||
|
parts := strings.Split(path, "/")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
log.Printf("Invalid firmware path for delete: %s", r.URL.Path)
|
||||||
|
http.Error(w, "Invalid firmware path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name := parts[0]
|
||||||
|
version := parts[1]
|
||||||
|
|
||||||
|
log.Printf("DELETE /firmware/%s/%s - %s", name, version, r.RemoteAddr)
|
||||||
|
|
||||||
|
// Delete firmware using service
|
||||||
|
if err := h.service.DeleteFirmware(name, version); err != nil {
|
||||||
|
if strings.Contains(err.Error(), "not found") {
|
||||||
|
log.Printf("Firmware not found for deletion: %s/%s", name, version)
|
||||||
|
http.Error(w, "Firmware not found", http.StatusNotFound)
|
||||||
|
} else {
|
||||||
|
log.Printf("Failed to delete firmware: %v", err)
|
||||||
|
http.Error(w, "Failed to delete firmware: "+err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Successfully deleted firmware: %s/%s", name, version)
|
||||||
|
|
||||||
|
// Return success response
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"success": true,
|
||||||
|
"message": "Firmware deleted successfully",
|
||||||
|
"name": name,
|
||||||
|
"version": version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// HealthCheck provides a simple health check endpoint
|
// HealthCheck provides a simple health check endpoint
|
||||||
func (h *FirmwareHandler) HealthCheck(w http.ResponseWriter, r *http.Request) {
|
func (h *FirmwareHandler) HealthCheck(w http.ResponseWriter, r *http.Request) {
|
||||||
response := models.HealthResponse{Status: "healthy"}
|
response := models.HealthResponse{Status: "healthy"}
|
||||||
|
|||||||
@@ -80,3 +80,23 @@ func (r *FirmwareRepository) GetFirmwareRecords(name, version string) ([]models.
|
|||||||
|
|
||||||
return records, nil
|
return records, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteFirmwareMetadata deletes firmware metadata from the database
|
||||||
|
func (r *FirmwareRepository) DeleteFirmwareMetadata(name, version string) error {
|
||||||
|
query := `DELETE FROM firmware WHERE name = ? AND version = ?`
|
||||||
|
result, err := r.db.Exec(query, name, version)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to delete firmware metadata: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rowsAffected, err := result.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get rows affected: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rowsAffected == 0 {
|
||||||
|
return fmt.Errorf("firmware not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -110,6 +110,31 @@ func (s *FirmwareService) GetFirmwarePath(name, version string) (string, error)
|
|||||||
return s.storage.GetFirmwareBinaryPath(name, version), nil
|
return s.storage.GetFirmwareBinaryPath(name, version), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteFirmware deletes firmware binary and metadata
|
||||||
|
func (s *FirmwareService) DeleteFirmware(name, version string) error {
|
||||||
|
// Validate required fields
|
||||||
|
if name == "" || version == "" {
|
||||||
|
return fmt.Errorf("name and version are required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if firmware exists
|
||||||
|
if !s.storage.FirmwareExists(name, version) {
|
||||||
|
return fmt.Errorf("firmware not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete from database first
|
||||||
|
if err := s.repo.DeleteFirmwareMetadata(name, version); err != nil {
|
||||||
|
return fmt.Errorf("failed to delete firmware metadata: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete firmware binary
|
||||||
|
if err := s.storage.DeleteFirmwareBinary(name, version); err != nil {
|
||||||
|
return fmt.Errorf("failed to delete firmware binary: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// groupFirmwareByName groups firmware records by name
|
// groupFirmwareByName groups firmware records by name
|
||||||
func (s *FirmwareService) groupFirmwareByName(records []models.FirmwareRecord) []models.GroupedFirmware {
|
func (s *FirmwareService) groupFirmwareByName(records []models.FirmwareRecord) []models.GroupedFirmware {
|
||||||
nameMap := make(map[string][]models.FirmwareRecord)
|
nameMap := make(map[string][]models.FirmwareRecord)
|
||||||
|
|||||||
@@ -55,3 +55,20 @@ func (fs *FileStorage) FirmwareExists(name, version string) bool {
|
|||||||
_, err := os.Stat(filePath)
|
_, err := os.Stat(filePath)
|
||||||
return !os.IsNotExist(err)
|
return !os.IsNotExist(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteFirmwareBinary deletes a firmware binary and its directory
|
||||||
|
func (fs *FileStorage) DeleteFirmwareBinary(name, version string) error {
|
||||||
|
// Get directory path: registry/<name>/<version>/
|
||||||
|
dirPath := filepath.Join(fs.registryPath, name, version)
|
||||||
|
|
||||||
|
// Remove the entire version directory
|
||||||
|
if err := os.RemoveAll(dirPath); err != nil {
|
||||||
|
return fmt.Errorf("failed to delete firmware directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to remove the name directory if it's empty
|
||||||
|
nameDir := filepath.Join(fs.registryPath, name)
|
||||||
|
os.Remove(nameDir) // Ignore error, directory might not be empty
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user