Skip to content

Commit 2f1843f

Browse files
feat: create cvm service, and config (#21)
1 parent 6374d5a commit 2f1843f

File tree

6 files changed

+160
-146
lines changed

6 files changed

+160
-146
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
apploader/conf/local.yml
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package config
2+
3+
import "os"
4+
5+
// Config holds application configuration
6+
type Config struct {
7+
Server ServerConfig
8+
Cvm CvmConfig
9+
}
10+
11+
// ServerConfig holds server configuration
12+
type ServerConfig struct {
13+
Port string
14+
}
15+
16+
// CvmConfig holds cvm configuration
17+
type CvmConfig struct {
18+
ConfigPath string
19+
SupervisorPath string
20+
SupervisorTemplatePath string
21+
}
22+
23+
// Load loads configuration from environment variables
24+
func Load() *Config {
25+
return &Config{
26+
Server: ServerConfig{
27+
Port: getEnv("PORT", ":9090"),
28+
},
29+
Cvm: CvmConfig{
30+
ConfigPath: getEnv("CVM_CONFIG_PATH", "/workplace/cvm-app/config/app.yml"),
31+
SupervisorPath: getEnv("SUPERVISOR_PATH", "/workplace/supervisord/apploader"),
32+
SupervisorTemplatePath: getEnv("SUPERVISOR_TEMPLATE_PATH", "conf/supervisord.ini.template"),
33+
},
34+
}
35+
}
36+
37+
// getEnv gets an environment variable with a fallback default value
38+
func getEnv(key, defaultValue string) string {
39+
if value := os.Getenv(key); value != "" {
40+
return value
41+
}
42+
return defaultValue
43+
}

apploader/internal/cvm/cvm.go

Lines changed: 62 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,94 @@
11
package cvm
22

3-
/*
4-
#include <unistd.h>
5-
#include <stdio.h>
6-
#include <stdlib.h>
7-
*/
8-
import "C"
93
import (
4+
"apploader/internal/config"
105
"apploader/internal/secret"
6+
"apploader/pkg/command"
117
"apploader/pkg/conversion"
128
"apploader/pkg/file"
139
"fmt"
1410
"log"
1511
"os"
16-
"os/exec"
1712
"path"
1813
"strings"
19-
"syscall"
2014
"text/template"
21-
"time"
22-
"unsafe"
2315

2416
"gopkg.in/yaml.v3"
2517
)
2618

2719
const (
28-
JOB = "job"
29-
SERVER = "server"
30-
DockerApp = "dockerApp"
31-
APP = "app"
20+
JOB = "job"
21+
SERVER = "server"
3222
)
3323

34-
const (
35-
SUPERVISOR_PATH = "/workplace/supervisord/apploader"
36-
)
37-
38-
func DoJob(ca *TaskInfo) error {
39-
if ca.Type != JOB {
40-
return fmt.Errorf("this task is not a job")
41-
}
42-
43-
envs := make([]string, 0)
44-
for k, v := range secret.Secret {
45-
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
46-
}
47-
48-
if ca.Env != nil {
49-
userEnv, ok := ca.Env.(map[string]interface{})
50-
if !ok {
51-
return fmt.Errorf("user env format error")
52-
}
53-
54-
for k, v := range userEnv {
55-
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
56-
}
57-
}
58-
59-
log.Printf("entrypoint is %s", ca.Entrypoint)
60-
return RunCommand(ca.Entrypoint, envs, ca.Args...)
61-
24+
type CvmBootManager interface {
25+
Start()
6226
}
6327

64-
func RunCommand(name string, envs []string, arg ...string) error {
65-
cmd := exec.Command(name, arg...)
28+
type cvmBootManager struct {
29+
config *config.CvmConfig
30+
cvmBootSequence *CvmBootSequence
31+
}
6632

67-
cmd.Dir = path.Dir(name)
68-
//
69-
stdout, err := cmd.StdoutPipe()
70-
cmd.Stderr = cmd.Stdout
71-
cmd.Env = envs
33+
// NewCvmBootManager creates a new cvm service
34+
func NewCvmBootManager(config *config.CvmConfig) (CvmBootManager, error) {
35+
service := &cvmBootManager{config: config}
36+
cvmBootSequence, err := service.loadConfig()
7237
if err != nil {
73-
return err
74-
}
75-
if err = cmd.Start(); err != nil {
76-
return err
77-
}
78-
//
79-
for {
80-
tmp := make([]byte, 128)
81-
_, err := stdout.Read(tmp)
82-
fmt.Print(string(tmp))
83-
if err != nil {
84-
break
85-
}
38+
return nil, err
8639
}
87-
if err = cmd.Wait(); err != nil {
88-
if ex, ok := err.(*exec.ExitError); ok {
89-
cmdExitStatus := ex.Sys().(syscall.WaitStatus).ExitStatus()
90-
log.Println(cmdExitStatus)
91-
}
92-
log.Println(err)
93-
return err
94-
}
95-
return nil
40+
service.cvmBootSequence = cvmBootSequence
41+
return service, nil
9642
}
9743

98-
func Execv(main string, args ...string) {
99-
workdir := path.Dir(main)
100-
if err := os.Chdir(workdir); err != nil {
101-
log.Fatalf("change to work dir failed, error: %s\n", err.Error())
102-
}
44+
// Start starts the cvm service
45+
func (s *cvmBootManager) Start() {
46+
s.startTask(s.cvmBootSequence.CvmAssistants)
47+
s.startTask(s.cvmBootSequence.AppInfo)
48+
}
10349

104-
sizeOfArgs_C := len(args) + 2 // +2 for [0]=main [1:end]=args [end]=nil
105-
Args_C := make([]*C.char, sizeOfArgs_C)
106-
Args_C[0] = C.CString(main)
107-
defer C.free(unsafe.Pointer(Args_C[0]))
108-
for i, arg := range args {
109-
Args_C[i+1] = C.CString(arg)
110-
defer C.free(unsafe.Pointer(Args_C[i+1]))
50+
// loadConfig loads the cvm app config
51+
func (cbm *cvmBootManager) loadConfig() (*CvmBootSequence, error) {
52+
appfile, err := os.ReadFile(cbm.config.ConfigPath)
53+
if err != nil {
54+
return nil, fmt.Errorf("read %s failed, error: %s", cbm.config.ConfigPath, err.Error())
11155
}
112-
Args_C[sizeOfArgs_C-1] = nil
113-
re := C.execv(C.CString(main), (**C.char)(unsafe.Pointer(&Args_C[0])))
114-
if re != 0 {
115-
log.Fatalf("execv %s failed, code is %d\n", main, re)
56+
cvmBootSequence := new(CvmBootSequence)
57+
err = yaml.Unmarshal(appfile, &cvmBootSequence)
58+
if err != nil {
59+
return nil, fmt.Errorf("unmarshal %s failed, error: %s", cbm.config.ConfigPath, err.Error())
11660
}
117-
return
61+
return cvmBootSequence, nil
11862
}
11963

120-
func ExecvDockerApp(ca *TaskInfo) {
121-
if ca.Type != DockerApp {
122-
log.Fatalf("task is not a docker app")
64+
func (cbm *cvmBootManager) DoJob(taskInfo *TaskInfo) error {
65+
if taskInfo.Type != JOB {
66+
return fmt.Errorf("this task is not a job")
12367
}
12468

69+
envs := make([]string, 0)
12570
for k, v := range secret.Secret {
126-
err := os.Setenv(k, v)
127-
if err != nil {
128-
log.Fatalf("set secret env failed, error: %s\n", err.Error())
129-
}
71+
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
13072
}
13173

132-
if ca.Env != nil {
133-
userEnv, ok := ca.Env.(map[string]interface{})
74+
if taskInfo.Env != nil {
75+
userEnv, ok := taskInfo.Env.(map[string]interface{})
13476
if !ok {
135-
log.Fatalf("user env format error")
77+
return fmt.Errorf("user env format error")
13678
}
13779

13880
for k, v := range userEnv {
139-
err := os.Setenv(k, v.(string))
140-
if err != nil {
141-
log.Fatalf("set app env failed, error: %s\n", err.Error())
142-
}
81+
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
14382
}
14483
}
14584

146-
Execv(ca.Entrypoint, ca.Args...)
85+
log.Printf("entrypoint is %s", taskInfo.Entrypoint)
86+
return command.RunCommand(taskInfo.Entrypoint, envs, taskInfo.Args...)
87+
14788
}
14889

149-
func CreateSevers(ca *TaskInfo) error {
150-
if ca.Type != SERVER {
90+
func (cbm *cvmBootManager) CreateSevers(taskInfo *TaskInfo) error {
91+
if taskInfo.Type != SERVER {
15192
return fmt.Errorf("task is not a server")
15293
}
15394

@@ -158,8 +99,8 @@ func CreateSevers(ca *TaskInfo) error {
15899
// envs = append(envs, fmt.Sprintf("%s=%s", k, v))
159100
//}
160101

161-
if ca.Env != nil {
162-
userEnv, ok := ca.Env.(map[string]interface{})
102+
if taskInfo.Env != nil {
103+
userEnv, ok := taskInfo.Env.(map[string]interface{})
163104
if !ok {
164105
return fmt.Errorf("user env format error")
165106
}
@@ -170,84 +111,61 @@ func CreateSevers(ca *TaskInfo) error {
170111
}
171112

172113
sConf := new(SupervisorConf)
173-
sConf.Name = ca.Name
174-
sConf.Command = ca.Entrypoint + " " + strings.Join(ca.Args, " ")
175-
sConf.Workplace = path.Dir(ca.Entrypoint)
114+
sConf.Name = taskInfo.Name
115+
sConf.Command = taskInfo.Entrypoint + " " + strings.Join(taskInfo.Args, " ")
116+
sConf.Workplace = path.Dir(taskInfo.Entrypoint)
176117
sConf.Environment = strings.Join(envs, ",")
177-
sConf.Priority = ca.Priority
118+
sConf.Priority = taskInfo.Priority
178119

179-
tmpl, err := template.ParseFiles("conf/supervisord.ini.template")
120+
tmpl, err := template.ParseFiles(cbm.config.SupervisorTemplatePath)
180121
if err != nil {
181-
return fmt.Errorf("parse supervisord template file failed, error: %s\n", err.Error())
122+
return fmt.Errorf("parse %s failed, error: %s", cbm.config.SupervisorTemplatePath, err.Error())
182123
}
183124

184-
supervisordINIPath := path.Join(SUPERVISOR_PATH, fmt.Sprintf("%s.ini", ca.Name))
125+
supervisordINIPath := path.Join(cbm.config.SupervisorPath, fmt.Sprintf("%s.ini", taskInfo.Name))
185126
if file.IsFile(supervisordINIPath) {
186127
os.RemoveAll(supervisordINIPath)
187128
}
188129

189130
f, err := os.Create(supervisordINIPath)
190131
if err != nil {
191-
return fmt.Errorf("create supervisord.ini failed, error: %s\n", err.Error())
132+
return fmt.Errorf("create %s failed, error: %s", supervisordINIPath, err.Error())
192133
}
193134
defer f.Close()
194135

195136
if err := tmpl.Execute(f, sConf); err != nil {
196-
return fmt.Errorf("file the supervisord.ini failed, error: %s\n", err.Error())
137+
return fmt.Errorf("fill the %s failed, error: %s", supervisordINIPath, err.Error())
197138
}
198139

199140
return nil
200141
}
201142

202-
func Start() {
203-
appfile, err := os.ReadFile("conf/app.yml")
204-
if err != nil {
205-
log.Fatalf("read app.yml failed, error: %s\n", err.Error())
206-
}
207-
cvmApp := new(CvmApp)
208-
err = yaml.Unmarshal(appfile, &cvmApp)
209-
if err != nil {
210-
log.Fatalf("unmarshal app.yml failed, error: %s\n", err.Error())
211-
}
212-
time.Sleep(5 * time.Second)
213-
214-
log.Println("do all the job over")
215-
216-
startTask(cvmApp.CvmAssistants)
217-
218-
startTask(cvmApp.AppInfo)
219-
}
220-
221-
func startTask(tasks []*TaskInfo) {
143+
func (cbm *cvmBootManager) startTask(tasks []*TaskInfo) {
222144
for i, t := range tasks {
223145
switch t.Type {
224146
case JOB:
225147
log.Printf("begin to do job %s\n", t.Name)
226-
err := DoJob(t)
148+
err := cbm.DoJob(t)
227149
if err != nil {
228150
log.Fatalf("do job %s failed, error: %s\n", t.Name, err.Error())
229151
}
230152
log.Printf("end to do job %s\n", t.Name)
231153
case SERVER:
232154
log.Printf("begin to deploy server %s\n", t.Name)
233155
t.Priority = i + 2
234-
err := CreateSevers(t)
156+
err := cbm.CreateSevers(t)
235157
if err != nil {
236158
log.Fatalf("deploy server %s failed, error: %s\n", t.Name, err)
237159
}
238-
err = RunCommand("supervisorctl", nil, "update")
160+
err = command.RunCommand("supervisorctl", nil, "update")
239161
if err != nil {
240162
log.Fatalf("update supervisor conf failed, error: %s", err.Error())
241163
}
242-
err = RunCommand("supervisorctl", nil, "start", t.Name)
164+
err = command.RunCommand("supervisorctl", nil, "start", t.Name)
243165
if err != nil {
244166
log.Fatalf("start %s failed, error: %s", t.Name, err.Error())
245167
}
246168
log.Printf("end to deply server %s\n", t.Name)
247-
case DockerApp:
248-
log.Printf("begin to run docker app %s\n", t.Name)
249-
log.Printf("docker app will only run the first app\n")
250-
ExecvDockerApp(t)
251169
default:
252170
log.Fatalf("task type: %s does not support", t.Type)
253171
}

apploader/internal/cvm/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package cvm
22

3-
// CvmApp is the main application configuration
4-
type CvmApp struct {
3+
// CvmBootSequence is the main application configuration
4+
type CvmBootSequence struct {
55
Kind string `yaml:"kind"`
66
AppInfo []*TaskInfo `yaml:"app"`
77
CvmAssistants []*TaskInfo `yaml:"csvAssistants"`

apploader/main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
package main
22

33
import (
4+
"apploader/internal/config"
45
"apploader/internal/cvm"
56
"apploader/internal/secret"
67
"log"
78
"os"
9+
"time"
810
)
911

1012
func main() {
1113
log.SetFlags(log.Lshortfile | log.LstdFlags)
14+
15+
cfg := config.Load()
16+
cvm, err := cvm.NewCvmBootManager(&cfg.Cvm)
17+
if err != nil {
18+
log.Fatalf("failed to create cvm boot manager: %v", err)
19+
}
1220
go secret.StartSecretServer()
21+
time.Sleep(2 * time.Second) // wait for secret server to start
1322
cvm.Start()
1423
os.Exit(0)
1524
}

0 commit comments

Comments
 (0)