http 핸들러 추가
This commit is contained in:
190
server/http_api.go
Normal file
190
server/http_api.go
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"go-ayo/logger"
|
||||||
|
"houston/shared"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *houstonHandler) GetAgents(w http.ResponseWriter, r *http.Request) {
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.Encode(h.Operation().Hosts())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *houstonHandler) GetDeploySources(w http.ResponseWriter, r *http.Request) {
|
||||||
|
files, err := os.ReadDir("deploys")
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
getVersions := func(name string) []string {
|
||||||
|
var out []string
|
||||||
|
files, _ := os.ReadDir(path.Join("deploys", name))
|
||||||
|
for _, fd := range files {
|
||||||
|
if fd.IsDir() {
|
||||||
|
out = append(out, fd.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make(map[string][]string)
|
||||||
|
for _, fd := range files {
|
||||||
|
if fd.IsDir() {
|
||||||
|
out[fd.Name()] = getVersions(fd.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.Encode(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *houstonHandler) Upload(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// <form action="/houston" method="post" enctype="multipart/form-data">
|
||||||
|
// <input type="file" name="file">
|
||||||
|
// <input type="text" name="name">
|
||||||
|
// <input type="text" name="version">
|
||||||
|
// <input type="submit" value="업로드">
|
||||||
|
// </form>
|
||||||
|
file, header, err := r.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
contents, err := io.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
version := r.FormValue("version")
|
||||||
|
name := r.FormValue("name")
|
||||||
|
ext := path.Ext(header.Filename)
|
||||||
|
|
||||||
|
// deploys 폴더는 파일시스템 서비스이므로 다운로드 가능
|
||||||
|
filename := path.Join("deploys", name, version, name+ext)
|
||||||
|
if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 파일 저장
|
||||||
|
err = os.WriteFile(filename, contents, 0644)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *houstonHandler) Deploy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// <form action="/houston" method="post" enctype="multipart/form-data">
|
||||||
|
// <input type="text" name="name">
|
||||||
|
// <input type="text" name="version">
|
||||||
|
// <input type="text" name="targets">
|
||||||
|
// <input type="submit" value="업로드">
|
||||||
|
// </form>
|
||||||
|
name := r.FormValue("name")
|
||||||
|
version := r.FormValue("version")
|
||||||
|
traws := r.FormValue("targets")
|
||||||
|
|
||||||
|
var targets []string
|
||||||
|
if err := json.Unmarshal([]byte(traws), &targets); err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(name) == 0 || len(version) == 0 || len(targets) == 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
relPath := path.Join("deploys", name, version)
|
||||||
|
files, err := os.ReadDir(relPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
latestTime := time.Time{}
|
||||||
|
var latestFilename string
|
||||||
|
for _, fd := range files {
|
||||||
|
if fd.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, _ := fd.Info()
|
||||||
|
if fi.ModTime().After(latestTime) {
|
||||||
|
latestFilename = fi.Name()
|
||||||
|
latestTime = fi.ModTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(latestFilename) == 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Operation().Deploy(MakeDeployRequest(
|
||||||
|
shared.DeployRequest{
|
||||||
|
Name: name,
|
||||||
|
Version: version,
|
||||||
|
Url: path.Join(relPath, latestFilename),
|
||||||
|
},
|
||||||
|
targets,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *houstonHandler) StartProcess(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// <form action="/houston" method="post" enctype="multipart/form-data">
|
||||||
|
// <input type="text" name="name">
|
||||||
|
// <input type="text" name="version">
|
||||||
|
// <input type="text" name="args">
|
||||||
|
// <input type="text" name="targets">
|
||||||
|
// <input type="submit" value="업로드">
|
||||||
|
// </form>
|
||||||
|
name := r.FormValue("name")
|
||||||
|
version := r.FormValue("version")
|
||||||
|
args := r.FormValue("args")
|
||||||
|
traws := r.FormValue("targets")
|
||||||
|
|
||||||
|
var targets []string
|
||||||
|
if err := json.Unmarshal([]byte(traws), &targets); err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(name) == 0 || len(version) == 0 || len(targets) == 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Operation().StartProcess(MakeStartProcessRequest(shared.StartProcessRequest{
|
||||||
|
Name: name,
|
||||||
|
Version: version,
|
||||||
|
Args: args, // 실행 파일 포함 e.g. "biglocal.exe -port=8090 -dev",
|
||||||
|
}, targets))
|
||||||
|
|
||||||
|
// svr.Operation().Start(server.MakeStartRequest(
|
||||||
|
// common.StartRequest{
|
||||||
|
// Name: "warehouse",
|
||||||
|
// Version: "latest",
|
||||||
|
// Args: "biglocal.exe -port=8090 -dev",
|
||||||
|
// },
|
||||||
|
// []string{"mountain"},
|
||||||
|
// ))
|
||||||
|
}
|
||||||
87
server/http_handler.go
Normal file
87
server/http_handler.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-ayo/common"
|
||||||
|
"go-ayo/logger"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"runtime/debug"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultMaxMemory = 32 << 10 // 32 KB
|
||||||
|
)
|
||||||
|
|
||||||
|
type HoustonServerWithHandler interface {
|
||||||
|
HoustonServer
|
||||||
|
RegisterHandlers(serveMux *http.ServeMux, prefix string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type houstonHandler struct {
|
||||||
|
HoustonServer
|
||||||
|
methods map[string]reflect.Method
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHoustonHandler() HoustonServerWithHandler {
|
||||||
|
var tmp *houstonHandler
|
||||||
|
|
||||||
|
methods := make(map[string]reflect.Method)
|
||||||
|
tp := reflect.TypeOf(tmp)
|
||||||
|
for i := 0; i < tp.NumMethod(); i++ {
|
||||||
|
method := tp.Method(i)
|
||||||
|
methods[strings.ToLower(method.Name)] = method
|
||||||
|
}
|
||||||
|
return &houstonHandler{
|
||||||
|
HoustonServer: NewServer(),
|
||||||
|
methods: methods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *houstonHandler) RegisterHandlers(serveMux *http.ServeMux, prefix string) error {
|
||||||
|
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, "houston"), h)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *houstonHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer func() {
|
||||||
|
s := recover()
|
||||||
|
if s != nil {
|
||||||
|
logger.Println(s)
|
||||||
|
debug.PrintStack()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
io.Copy(io.Discard, r.Body)
|
||||||
|
r.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
operation := r.FormValue("operation")
|
||||||
|
if len(operation) == 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
method, ok := h.methods[strings.ToLower(operation)]
|
||||||
|
if !ok {
|
||||||
|
// 없는 operation
|
||||||
|
logger.Println("fail to call api. operation is not valid :", operation)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.PostForm == nil {
|
||||||
|
r.ParseMultipartForm(defaultMaxMemory)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []reflect.Value{
|
||||||
|
reflect.ValueOf(h),
|
||||||
|
reflect.ValueOf(w),
|
||||||
|
reflect.ValueOf(r),
|
||||||
|
}
|
||||||
|
|
||||||
|
method.Func.Call(args)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user