9 Commits

Author SHA1 Message Date
cd45bcf5c5 remove comment 2026-05-15 01:25:24 -04:00
8423cf5f69 working commit 2026-05-15 00:50:34 -04:00
62be5ddda7 test 2026-05-15 00:39:51 -04:00
3a88c8d878 dockerfile: update 2026-05-15 00:39:51 -04:00
25d01298e5 println -> log 2026-05-15 00:39:51 -04:00
fd53e28143 api: fix routes 2026-05-15 00:39:51 -04:00
c5e773a694 gofmt 2026-05-15 00:39:51 -04:00
cd47863622 update docker 2026-05-15 00:39:51 -04:00
3775894a5b update docker 2026-05-15 00:39:51 -04:00
7 changed files with 111 additions and 88 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "web"]
path = web
url = ssh://git@git.coopcloud.tech:2222/toolshed/coop-cloud-front.git

View File

@ -1,15 +1,30 @@
FROM golang:1.25 FROM golang:1.25
RUN mkdir /backend RUN mkdir /backend
COPY . /backend/ COPY --parents ["api", "cli", "internal", "go.mod", "go.sum", "app.go", "/backend/"]
RUN go build -C /backend -o app RUN go build -C /backend -o gobackend
EXPOSE 3000
FROM node FROM node
RUN mkdir /frontend RUN mkdir /home/node/wizard
WORKDIR /frontend COPY --from=0 /backend/gobackend /home/node/wizard/gobackend
RUN git clone https://git.coopcloud.tech/BornDeleuze/coop-cloud-front
EXPOSE 5173 COPY --parents web /home/node/wizard
WORKDIR /home/node/wizard/web
RUN npm install .
USER node
RUN curl https://install.abra.coopcloud.tech | bash
ENV ABRA_BIN=/home/node/.local/bin/abra
RUN $ABRA_BIN recipe fetch -a
COPY ./start.sh / COPY ./start.sh /
COPY --from=0 /backend/app /backend/app COPY dot_abra /home/node/.abra/
ENTRYPOINT [ "/start.sh" ] COPY ssh_config /home/node/.ssh/config
COPY id_ed25519_* /home/node/.ssh/
USER root
RUN chown -R node /home/node/
USER node
EXPOSE 5173 3000
# ENV VITE_API_URL=http://localhost:3000/api
CMD [ "/start.sh" ]

View File

@ -2,7 +2,6 @@
A Go service that exposes RESTful API endpoints to manage Abra programmatically. A Go service that exposes RESTful API endpoints to manage Abra programmatically.
Integrates with https://git.coopcloud.tech/BornDeleuze/coop-cloud-front. Integrates with https://git.coopcloud.tech/BornDeleuze/coop-cloud-front.
## Getting started ## Getting started
- Edit the front-end application to turn off mock mode in `src/routes/Authenticated/App.tsx` and `src/routes/Authenticated/Apps.tsx`. - Edit the front-end application to turn off mock mode in `src/routes/Authenticated/App.tsx` and `src/routes/Authenticated/Apps.tsx`.

View File

@ -1,9 +1,11 @@
package api package api
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"log" "log"
"encoding/json"
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/upstream/stack" "coopcloud.tech/abra/pkg/upstream/stack"
@ -11,19 +13,22 @@ import (
configPkg "coopcloud.tech/abra/pkg/config" configPkg "coopcloud.tech/abra/pkg/config"
deployPkg "coopcloud.tech/abra/pkg/deploy" deployPkg "coopcloud.tech/abra/pkg/deploy"
composetypes "github.com/docker/cli/cli/compose/types"
"net/http" "net/http"
composetypes "github.com/docker/cli/cli/compose/types"
"coop-cloud-backend/internal" "coop-cloud-backend/internal"
) )
type abraHandler struct{
type abraHandler struct {
mux *http.ServeMux mux *http.ServeMux
} }
func newAbraHandler() *abraHandler { func newAbraHandler() *abraHandler {
h := &abraHandler{ h := &abraHandler{
mux: http.NewServeMux(), mux: http.NewServeMux(),
} }
h.mux.HandleFunc("/apps", func(w http.ResponseWriter, r *http.Request) { h.mux.HandleFunc("/api/abra/apps", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
@ -38,7 +43,7 @@ func newAbraHandler() *abraHandler {
http.Error(w, "Method not implemented", http.StatusMethodNotAllowed) http.Error(w, "Method not implemented", http.StatusMethodNotAllowed)
} }
}) })
h.mux.HandleFunc("/apps/{serverId}/{appId}/deploy", func(w http.ResponseWriter, r *http.Request) { h.mux.HandleFunc("/api/abra/apps/{serverId}/{appId}/deploy", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS") w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
@ -47,14 +52,14 @@ func newAbraHandler() *abraHandler {
return return
} }
switch r.Method{ switch r.Method {
case http.MethodPost: case http.MethodPost:
h.handleDeployApp(w, r, r.PathValue("appId"), r.PathValue("serverId")) h.handleDeployApp(w, r, r.PathValue("appId"), r.PathValue("serverId"))
default: default:
http.Error(w, "Method not implemented", http.StatusMethodNotAllowed) http.Error(w, "Method not implemented", http.StatusMethodNotAllowed)
} }
}) })
h.mux.HandleFunc("/servers", func(w http.ResponseWriter, r *http.Request) { h.mux.HandleFunc("/api/abra/servers", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
@ -73,8 +78,8 @@ func newAbraHandler() *abraHandler {
} }
func StartAPI() { func StartAPI() {
h := newAbraHandler() h := newAbraHandler()
fmt.Println("Server started on port 3000") log.Println("Server started on port 3000")
http.ListenAndServe(":3000", h) log.Fatal(http.ListenAndServe(":3000", h))
} }
func (h *abraHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h *abraHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@ -84,6 +89,7 @@ func (h *abraHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Delegate to internal mux // Delegate to internal mux
h.mux.ServeHTTP(w, r) h.mux.ServeHTTP(w, r)
} }
// func (h *appHandler) handleStartApp(w http.ResponseWriter, r *http.Request) { // func (h *appHandler) handleStartApp(w http.ResponseWriter, r *http.Request) {
// appName := r.PathValue("appName") // appName := r.PathValue("appName")
// w.Write([]byte("starting app: " + appName)) // w.Write([]byte("starting app: " + appName))
@ -111,7 +117,7 @@ func (h *abraHandler) handleDeployApp(w http.ResponseWriter, r *http.Request, ap
return return
} }
if deployMeta.IsDeployed { if deployMeta.IsDeployed {
log.Fatal("%s is already deployed", app.Name) log.Fatalf("%s is already deployed", app.Name)
InternalServerErrorHandler(w, r) InternalServerErrorHandler(w, r)
return return
} }
@ -204,36 +210,36 @@ func (h *abraHandler) handleDeployApp(w http.ResponseWriter, r *http.Request, ap
//commented code is to show deploy overview before deploy //commented code is to show deploy overview before deploy
/* /*
deployedVersion := configPkg.MISSING_DEFAULT deployedVersion := configPkg.MISSING_DEFAULT
if deployMeta.IsDeployed { if deployMeta.IsDeployed {
deployedVersion = deployMeta.Version deployedVersion = deployMeta.Version
if deployMeta.IsChaos { if deployMeta.IsChaos {
deployedVersion = deployMeta.ChaosVersion deployedVersion = deployMeta.ChaosVersion
}
}
ShowUnchanged := false
secretInfo, err := deployPkg.GatherSecretsForDeploy(cl, app, ShowUnchanged)
if err != nil {
log.Fatal(err)
InternalServerErrorHandler(w, r)
return
} }
}
ShowUnchanged := false
secretInfo, err := deployPkg.GatherSecretsForDeploy(cl, app, ShowUnchanged)
if err != nil {
log.Fatal(err)
InternalServerErrorHandler(w, r)
return
}
// Gather configs // Gather configs
configInfo, err := deployPkg.GatherConfigsForDeploy(cl, app, compose, app.Env, ShowUnchanged) configInfo, err := deployPkg.GatherConfigsForDeploy(cl, app, compose, app.Env, ShowUnchanged)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
InternalServerErrorHandler(w, r) InternalServerErrorHandler(w, r)
return return
} }
// Gather images // Gather images
imageInfo, err := deployPkg.GatherImagesForDeploy(cl, app, compose, ShowUnchanged) imageInfo, err := deployPkg.GatherImagesForDeploy(cl, app, compose, ShowUnchanged)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
InternalServerErrorHandler(w, r) InternalServerErrorHandler(w, r)
return return
}*/ }*/
stack.WaitTimeout, err = appPkg.GetTimeoutFromLabel(compose, stackName) stack.WaitTimeout, err = appPkg.GetTimeoutFromLabel(compose, stackName)
if err != nil { if err != nil {
@ -287,7 +293,7 @@ func (h *abraHandler) handleListApps(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
log.Printf("Error getting app %s: %s\n", appName, err) log.Printf("Error getting app %s: %s\n", appName, err)
InternalServerErrorHandler(w, r) InternalServerErrorHandler(w, r)
return return
} }
remoteApps = append(remoteApps, remoteApp) remoteApps = append(remoteApps, remoteApp)
} }
@ -295,7 +301,7 @@ func (h *abraHandler) handleListApps(w http.ResponseWriter, r *http.Request) {
appStatuses, err := GetAppStatuses(remoteApps) appStatuses, err := GetAppStatuses(remoteApps)
if err != nil { if err != nil {
log.Printf("GetAppStatuses Falied\n") log.Printf("GetAppStatuses Falied\n")
fmt.Println("Error: ", err) log.Println("Error: ", err)
InternalServerErrorHandler(w, r) InternalServerErrorHandler(w, r)
return return
} }
@ -345,39 +351,39 @@ func appTransposeUndeployed(app appPkg.App) AbraApp {
version = "unknown" version = "unknown"
} }
return AbraApp{ return AbraApp{
AppName: app.Name, AppName: app.Name,
Server: app.Server, Server: app.Server,
Recipe: app.Recipe.Name, Recipe: app.Recipe.Name,
Domain: app.Domain, Domain: app.Domain,
Chaos: "false", Chaos: "false",
Status: "undeployed", Status: "undeployed",
ChaosVersion: "unknown", ChaosVersion: "unknown",
Version: version, Version: version,
Upgrade: "latest", Upgrade: "latest",
} }
} }
func appTranspose(app appPkg.App, psInfo map[string]string) AbraApp { func appTranspose(app appPkg.App, psInfo map[string]string) AbraApp {
return AbraApp{ return AbraApp{
AppName: app.Name, AppName: app.Name,
Server: app.Server, Server: app.Server,
Recipe: app.Recipe.Name, Recipe: app.Recipe.Name,
Domain: app.Domain, Domain: app.Domain,
Chaos: psInfo["chaos"], Chaos: psInfo["chaos"],
Status: psInfo["status"], Status: psInfo["status"],
ChaosVersion: getOrDefault(psInfo, "chaosVersion", "unknown"), ChaosVersion: getOrDefault(psInfo, "chaosVersion", "unknown"),
Version: psInfo["version"], Version: psInfo["version"],
Upgrade: "latest", Upgrade: "latest",
} }
} }
func getOrDefault(m map[string]string, key, def string) string { func getOrDefault(m map[string]string, key, def string) string {
if v, ok := m[key]; ok { if v, ok := m[key]; ok {
return v return v
} }
return def return def
} }
func (h *abraHandler) handleListServers (w http.ResponseWriter, r *http.Request) { func (h *abraHandler) handleListServers(w http.ResponseWriter, r *http.Request) {
servers, err := GetServers() servers, err := GetServers()
if err != nil { if err != nil {
InternalServerErrorHandler(w, r) InternalServerErrorHandler(w, r)
@ -391,11 +397,11 @@ func (h *abraHandler) handleListServers (w http.ResponseWriter, r *http.Request)
abraServers := make([]AbraServer, 0, len(servers)) abraServers := make([]AbraServer, 0, len(servers))
for i := range len(servers) { for i := range len(servers) {
abraServers = append(abraServers, abraServers = append(abraServers,
AbraServer{ AbraServer{
Name: serverNames[i], Name: serverNames[i],
Host: servers[i], Host: servers[i],
}, },
) )
} }
jsonBytes, err := json.Marshal(abraServers) jsonBytes, err := json.Marshal(abraServers)
if err != nil { if err != nil {

8
app.go
View File

@ -49,7 +49,7 @@ import (
// return envMap, nil // return envMap, nil
// } // }
func printApp(app appPkg.App) error { func printApp(app appPkg.App) error {
fmt.Printf("Name: %s | Domain: %s | Server: %s | Path: %s", log.Printf("Name: %s | Domain: %s | Server: %s | Path: %s",
app.Name, app.Domain, app.Server, app.Path) app.Name, app.Domain, app.Server, app.Path)
return nil return nil
} }
@ -64,13 +64,13 @@ func connectToContainer(app appPkg.App, serviceName string) {
filters := filters.NewArgs() filters := filters.NewArgs()
filters.Add("name", stackAndServiceName) filters.Add("name", stackAndServiceName)
fmt.Printf("HI?") log.Printf("HI?")
targetContainer, err := containerPkg.GetContainer(context.Background(), cl, filters, false) targetContainer, err := containerPkg.GetContainer(context.Background(), cl, filters, false)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
fmt.Printf("Container ID: %s", targetContainer.ID) log.Printf("Container ID: %s", targetContainer.ID)
} }
func main() { func main() {
appNames, err := appPkg.GetAppNames() appNames, err := appPkg.GetAppNames()
@ -79,7 +79,7 @@ func main() {
} }
for _, appName := range appNames { for _, appName := range appNames {
val := fmt.Sprintf("app , %v", appName) val := fmt.Sprintf("app , %v", appName)
fmt.Println(val) log.Println(val)
} }
api.StartAPI() api.StartAPI()

View File

@ -1,6 +1,5 @@
#!/bin/bash #!/bin/bash
/backend/app & /home/node/wizard/gobackend &
cd /frontend npm run dev -- --host
npm run dev

1
web Submodule

Submodule web added at 08510b136e