houston package 독립
This commit is contained in:
228
client/deploy.go
Normal file
228
client/deploy.go
Normal file
@ -0,0 +1,228 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go-ayo/common/logger"
|
||||
"houston/shared"
|
||||
"houston/shared/protos"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/encoding/korean"
|
||||
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
func download(dir string, urlpath string, accessToken string) (string, error) {
|
||||
parsed, err := url.Parse(urlpath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("GET", urlpath, nil)
|
||||
if len(accessToken) > 0 {
|
||||
req.Header.Add("Authorization", accessToken)
|
||||
}
|
||||
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.51")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("download failed : %d %s", resp.StatusCode, parsed.Path)
|
||||
}
|
||||
|
||||
out, err := os.Create(path.Join(dir, path.Base(parsed.Path)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return out.Name(), nil
|
||||
}
|
||||
|
||||
func unzip(fname string) error {
|
||||
archive, err := zip.OpenReader(fname)
|
||||
if err != nil {
|
||||
os.Remove(fname)
|
||||
return err
|
||||
}
|
||||
defer archive.Close()
|
||||
|
||||
verpath := path.Dir(fname)
|
||||
for _, f := range archive.File {
|
||||
var name string
|
||||
if f.NonUTF8 {
|
||||
name, _, _ = transform.String(korean.EUCKR.NewDecoder(), f.Name)
|
||||
} else {
|
||||
name = f.Name
|
||||
}
|
||||
|
||||
filePath := path.Join(verpath, name)
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(filePath, os.ModePerm)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(path.Dir(filePath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileInArchive, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dstFile.Close()
|
||||
fileInArchive.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func untar(fname string) error {
|
||||
file, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
verpath := path.Dir(fname)
|
||||
tarReader := tar.NewReader(file)
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.MkdirAll(path.Join(verpath, header.Name), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
case tar.TypeReg:
|
||||
fileWriter, err := os.Create(path.Join(verpath, header.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fileWriter.Close()
|
||||
|
||||
if _, err := io.Copy(fileWriter, tarReader); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("unknown type")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hc *houstonClient) prepareDeploy(name string, version string) (destPath string, err error) {
|
||||
// houston관리용임을 표시하기 위해 더미파일 생성
|
||||
defer func() {
|
||||
var flagf *os.File
|
||||
if _, err := os.Stat(path.Join(name, "@houston")); os.IsNotExist(err) {
|
||||
flagf, err = os.Create(path.Join(name, "@houston"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer flagf.Close()
|
||||
flagf.Write([]byte(hc.timestamp))
|
||||
}
|
||||
}()
|
||||
|
||||
verpath := path.Join("./", name, version)
|
||||
if _, err := os.Stat(verpath); os.IsNotExist(err) {
|
||||
// 없네? 만들면 된다.
|
||||
err = os.MkdirAll(verpath, fs.FileMode(os.O_WRONLY))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
// 있네? 재배포 가능한가?
|
||||
for _, child := range hc.childProcs {
|
||||
if child.version == version && child.name == name {
|
||||
// 이미 실행 중인 버전이다. 실패
|
||||
return "", fmt.Errorf("%s %s is already running. deploy is failed", name, version)
|
||||
}
|
||||
}
|
||||
// 재배포 가능
|
||||
}
|
||||
return verpath, nil
|
||||
}
|
||||
|
||||
func (hc *houstonClient) deploy(req *shared.DeployRequest) error {
|
||||
logger.Println("start deploying")
|
||||
root, err := hc.prepareDeploy(req.Name, req.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(req.Url, "http") {
|
||||
tks := strings.SplitN(hc.httpAddr, "://", 2)
|
||||
req.Url = fmt.Sprintf("%s://%s", tks[0], path.Join(tks[1], req.Url))
|
||||
}
|
||||
|
||||
logger.Println("start downloading", req.Url)
|
||||
// verpath에 배포 시작
|
||||
fname, err := download(root, req.Url, req.AccessToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch path.Ext(fname) {
|
||||
case ".zip":
|
||||
err = unzip(fname)
|
||||
case ".tar":
|
||||
err = untar(fname)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (hc *houstonClient) withdraw(req *shared.WithdrawRequest) error {
|
||||
fd, _ := os.Stat(path.Join("./", req.Name, req.Version))
|
||||
if fd != nil {
|
||||
if fd.IsDir() {
|
||||
for _, running := range hc.childProcs {
|
||||
if running.name == req.Name && running.version == req.Version {
|
||||
// 회수하려는 버전이 돌고 있다
|
||||
if running.state != protos.ProcessState_Stopped {
|
||||
return fmt.Errorf("withdraw failed. %s@%s is still running", req.Name, req.Version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return os.RemoveAll(path.Join("./", req.Name, req.Version))
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("withdraw failed. %s@%s is not deployed", req.Name, req.Version)
|
||||
}
|
||||
Reference in New Issue
Block a user