93 lines
3.3 KiB
Go
93 lines
3.3 KiB
Go
// Copyright (C) 2026 Dcntrlized
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published
|
|
// by the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package actions
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
|
|
"git.dcntrlized.org/Dcntrlized/Maestro/lib/docker"
|
|
"git.dcntrlized.org/Dcntrlized/Maestro/lib/logger"
|
|
)
|
|
|
|
func RunAction(w http.ResponseWriter, r *http.Request) {
|
|
// Runs an action on the container specified by the actionName and containerId path parameters.
|
|
actionName := r.PathValue("actionName")
|
|
containerId := r.PathValue("containerId")
|
|
|
|
logger.Debug("Received request to run action %s on container id %s", actionName, containerId)
|
|
|
|
// Get IP address of the container using containerId
|
|
dockerClient, err := docker.NewDockerClient()
|
|
if err != nil {
|
|
http.Error(w, "Failed to create Docker client", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
inspectData, err := dockerClient.ContainerInspect(context.Background(), containerId)
|
|
if err != nil {
|
|
http.Error(w, "Failed to inspect container", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
network, _, err := docker.ExtractNetworkInfo(context.Background(), dockerClient, inspectData)
|
|
if err != nil {
|
|
http.Error(w, "Failed to extract network info", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Construct the URL for the action endpoint
|
|
actionURL := fmt.Sprintf("http://%s:%d/action/%s", network.IPAddress.Address, network.Ports[0].Host, actionName) // Assuming network.Ports[0] is the main port. Might change in the future
|
|
|
|
// Forward the request to the container's action endpoint
|
|
resp, err := http.Get(actionURL)
|
|
if err != nil {
|
|
logger.Debug("Failed to forward action request %s to container %s: %w", actionName, containerId, err)
|
|
http.Error(w, "Failed to forward request to container", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
bodyBytes, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
logger.Debug("Failed to read container error response body: %v", err)
|
|
}
|
|
|
|
responseBodyString := string(bodyBytes)
|
|
|
|
if resp.StatusCode == 404 {
|
|
logger.Info("The requested action does not exist")
|
|
http.Error(w, "The requested action does not exist", http.StatusNotFound)
|
|
}
|
|
|
|
logger.Info("Container responded with non-2xx code")
|
|
logger.Debug("Container: %s | Called URL: %s | Status: %d | Response: %s",
|
|
containerId, actionURL, resp.StatusCode, responseBodyString)
|
|
http.Error(w, "Container responded with non-2xx code", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
// Copy the response from the container back to the original response writer
|
|
w.WriteHeader(resp.StatusCode)
|
|
_, err = io.Copy(w, resp.Body)
|
|
if err != nil {
|
|
http.Error(w, "Failed to read response from container", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|