diff --git a/etc/boot.sh b/etc/boot.sh new file mode 100755 index 00000000..008d5ef2 --- /dev/null +++ b/etc/boot.sh @@ -0,0 +1,62 @@ +#! /bin/bash + +log() { + echo $* +} +prepare() { + log "prepare dir" + mkdir -p bin etc usr + mkdir -p var/log var/tmp var/run +} + +dir=/usr/local/context +[ -d "$1" ] && dir=$1 && shift +[ -d "$dir" ] && cd $dir + +bench=bench +[ -f bin/bench ] && bench=bin/bench + +pid=`cat var/run/bench.pid` + +case $1 in + help) + cat<var/log/error.log && break + log "restarting..." + sleep 3 + done + ;; + stop) + log "kill" quit + kill -QUIT $pid + ;; + restart) + log "kill" usr1 + kill -USR1 $pid + ;; +esac diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index bbd52359..2febe7e1 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -54,6 +54,11 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server return &CLI{Context: c} } func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { + name, _ := os.Hostname() + m.Conf("runtime", "hostname", name) + m.Conf("runtime", "pid", os.Getpid()) + m.Conf("runtime", "GOOS", runtime.GOOS) + m.Conf("runtime", "GOARCH", runtime.GOARCH) return cli } func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { @@ -98,6 +103,8 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "nshell": &ctx.Cache{Name: "nshell", Value: "0", Help: "终端数量"}, }, Configs: map[string]*ctx.Config{ + "runtime": &ctx.Config{Name: "runtime", Value: map[string]interface{}{}, Help: "运行环境"}, + "init_shy": &ctx.Config{Name: "init_shy", Value: "etc/init.shy", Help: "启动脚本"}, "exit_shy": &ctx.Config{Name: "exit_shy", Value: "etc/exit.shy", Help: "启动脚本"}, "cmd_script": &ctx.Config{Name: "cmd_script", Value: map[string]interface{}{ @@ -287,6 +294,14 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } return }}, + "exit": &ctx.Command{Name: "exit code", Help: "停止服务", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + m.Cmd("cli.source", m.Conf("exit_shy")) + go func() { + time.Sleep(time.Second * 3) + os.Exit(kit.Int(arg[0])) + }() + return + }}, "alias": &ctx.Command{Name: "alias [short [long...]]|[delete short]|[import module [command [alias]]]", Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名, import导入模块所有命令", diff --git a/src/contexts/gdb/gdb.go b/src/contexts/gdb/gdb.go index 23c1ed0d..f7145c96 100644 --- a/src/contexts/gdb/gdb.go +++ b/src/contexts/gdb/gdb.go @@ -82,12 +82,27 @@ func (gdb *GDB) Begin(m *ctx.Message, arg ...string) ctx.Server { func (gdb *GDB) Start(m *ctx.Message, arg ...string) bool { gdb.goon = make(chan os.Signal, 10) gdb.wait = make(chan interface{}, 10) - signal.Notify(gdb.goon, syscall.Signal(30)) + + m.Confm("signal", func(sig string, action string) { + m.Log("signal", "add %s %s", sig, action) + signal.Notify(gdb.goon, syscall.Signal(kit.Int(sig))) + }) + for { select { case sig := <-gdb.goon: - m.Log("error", "signal %v", sig) - gdb.Goon(nil, "cache", "read", "value") + action := m.Conf("signal", sig) + m.Log("signal", "signal %v %v", sig, action) + switch action { + case "quit": + m.Cmd("cli.exit", 0) + case "restart": + m.Cmd("cli.exit", 1) + case "upgrade": + m.Find("web.code").Cmd("upgrade", "system") + default: + // gdb.Goon(nil, "cache", "read", "value") + } } } return true @@ -103,6 +118,11 @@ func (gdb *GDB) Close(m *ctx.Message, arg ...string) bool { var Index = &ctx.Context{Name: "gdb", Help: "调试中心", Caches: map[string]*ctx.Cache{}, Configs: map[string]*ctx.Config{ + "signal": &ctx.Config{Name: "signal", Value: map[string]interface{}{ + "3": "quit", + "10": "restart", + "12": "upgrade", + }, Help: "信号"}, "debug": &ctx.Config{Name: "debug", Value: map[string]interface{}{"value": map[string]interface{}{"enable": false}, "trace": map[string]interface{}{"value": map[string]interface{}{"enable": true}}, "context": map[string]interface{}{"value": map[string]interface{}{"enable": false}, diff --git a/src/contexts/log/log.go b/src/contexts/log/log.go index 298c3578..4d2422f4 100644 --- a/src/contexts/log/log.go +++ b/src/contexts/log/log.go @@ -119,7 +119,7 @@ var Index = &ctx.Context{Name: "log", Help: "日志中心", }, Configs: map[string]*ctx.Config{ "logdir": &ctx.Config{Name: "logdir", Value: "var/log", Help: ""}, - "logpid": &ctx.Config{Name: "logpid", Value: "var/log/bench.pid", Help: ""}, + "logpid": &ctx.Config{Name: "logpid", Value: "var/run/bench.pid", Help: ""}, "output": &ctx.Config{Name: "output", Value: map[string]interface{}{ "error": map[string]interface{}{"value": map[string]interface{}{"file": "error.log", "meta": []interface{}{"time", "ship"}, "color_begin": "\033[31m", "color_end": "\033[0m"}}, "trace": map[string]interface{}{"value": map[string]interface{}{"file": "error.log", "meta": []interface{}{"time", "ship"}, "color_begin": "\033[32m", "color_end": "\033[0m"}}, diff --git a/src/contexts/ssh/ssh.go b/src/contexts/ssh/ssh.go index c11dd958..c3b5dd42 100644 --- a/src/contexts/ssh/ssh.go +++ b/src/contexts/ssh/ssh.go @@ -34,26 +34,26 @@ func (ssh *SSH) Close(m *ctx.Message, arg ...string) bool { var Index = &ctx.Context{Name: "ssh", Help: "集群中心", Caches: map[string]*ctx.Cache{ - "nhost": &ctx.Cache{Name: "nhost", Value: "0", Help: "主机数量"}, - "hostname": &ctx.Cache{Name: "hostname", Value: "shy", Help: "本机域名"}, + "nnode": &ctx.Cache{Name: "nnode", Value: "0", Help: "节点数量"}, + "nodename": &ctx.Cache{Name: "nodename", Value: "shy", Help: "本机域名"}, }, Configs: map[string]*ctx.Config{ - "host": &ctx.Config{Name: "host", Value: map[string]interface{}{}, Help: "主机信息"}, + "node": &ctx.Config{Name: "node", Value: map[string]interface{}{}, Help: "主机信息"}, "hostport": &ctx.Config{Name: "hostport", Value: "", Help: "主机域名"}, - "hostname": &ctx.Config{Name: "hostname", Value: "com", Help: "主机域名"}, + "nodename": &ctx.Config{Name: "nodename", Value: "com", Help: "主机域名"}, "current": &ctx.Config{Name: "current", Value: "", Help: "当前主机"}, "timer": &ctx.Config{Name: "timer", Value: "", Help: "当前主机"}, }, Commands: map[string]*ctx.Command{ - "remote": &ctx.Command{Name: "remote listen|dial args...", Help: "远程连接", Form: map[string]int{"right": 1, "hostname": 1}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + "remote": &ctx.Command{Name: "remote listen|dial args...", Help: "远程连接", Form: map[string]int{"right": 1, "nodename": 1}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if len(arg) == 0 { // 查看主机 - m.Cmdy("ctx.config", "host") + m.Cmdy("ctx.config", "node") return } switch arg[0] { case "redial": // 断线重连 - if !m.Caps("hostname") { + if !m.Caps("nodename") { m.Cmdx("remote", "dial", arg[1:]) } case "listen", "dial": @@ -66,8 +66,8 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", m.Conf("timer", m.Cmdx("cli.timer", "delete", m.Conf("timer"))) } - m.Spawn(nfs.Target()).Call(func(host *ctx.Message) *ctx.Message { - m.Confv("host", host.Result(1), map[string]interface{}{ // 添加主机 + m.Spawn(nfs.Target()).Call(func(node *ctx.Message) *ctx.Message { + m.Confv("node", node.Result(1), map[string]interface{}{ // 添加主机 "module": nfs.Format("target"), "create_time": m.Time(), "access_time": m.Time(), @@ -76,42 +76,42 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", }) m.Cap("stream", nfs.Format("target")) - m.Cap("hostname", host.Result(0)) + m.Cap("nodename", node.Result(0)) if !m.Confs("current") { - m.Conf("current", host.Result(1)) + m.Conf("current", node.Result(1)) } nfs.Free(func(nfs *ctx.Message) bool { // 连接中断 m.Conf("timer", m.Cmdx("cli.timer", "repeat", "10s", "context", "ssh", "remote", "redial", arg[1:])) - m.Log("info", "delete host %s", host.Result(1)) - delete(m.Confm("host"), host.Result(1)) - m.Cap("hostname", "") + m.Log("info", "delete node %s", node.Result(1)) + delete(m.Confm("node"), node.Result(1)) + m.Cap("nodename", "") m.Cap("stream", "") return true }) return nil - }, "send", "recv", "add", m.Confx("hostname")) + }, "send", "recv", "add", m.Confx("nodename")) } return nil }, "nfs.remote", arg) case "recv": switch arg[1] { case "add": - if host := m.Confm("host", arg[2]); host == nil { // 添加主机 - m.Confv("host", arg[2], map[string]interface{}{ + if node := m.Confm("node", arg[2]); node == nil { // 添加主机 + m.Confv("node", arg[2], map[string]interface{}{ "module": m.Format("source"), "create_time": m.Time(), "access_time": m.Time(), "username": m.Option("right"), "cm_target": "ctx.web.code", }) - } else if len(arg) > 3 && arg[3] == kit.Format(host["token"]) { // 断线重连 - host["access_time"] = m.Time() - host["module"] = m.Format("source") + } else if len(arg) > 3 && arg[3] == kit.Format(node["token"]) { // 断线重连 + node["access_time"] = m.Time() + node["module"] = m.Format("source") } else { // 域名冲突 - arg[2] = fmt.Sprintf("%s_%d", arg[2], m.Capi("nhost", 1)) - m.Confv("host", arg[2], map[string]interface{}{ + arg[2] = fmt.Sprintf("%s_%d", arg[2], m.Capi("nnode", 1)) + m.Confv("node", arg[2], map[string]interface{}{ "module": m.Format("source"), "create_time": m.Time(), "access_time": m.Time(), @@ -124,10 +124,10 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", m.Conf("current", arg[2]) } - m.Echo(arg[2]).Echo(m.Cap("hostname")).Back(m) + m.Echo(arg[2]).Echo(m.Cap("nodename")).Back(m) m.Sess("ms_source", false).Free(func(msg *ctx.Message) bool { // 断线清理 - m.Log("info", "delete host %s", arg[2]) - delete(m.Confm("host"), arg[2]) + m.Log("info", "delete node %s", arg[2]) + delete(m.Confm("node"), arg[2]) return true }) } @@ -136,23 +136,23 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", names, arg := strings.SplitN(arg[0], ".", 2), arg[1:] if names[0] == "" { // 本地执行 - host := m.Confm("host", m.Option("hostname")) - user := kit.Format(kit.Chain(host, "username")) + node := m.Confm("node", m.Option("nodename")) + user := kit.Format(kit.Chain(node, "username")) - sessid := m.Cmd("aaa.user", user, "ssh").Append("meta") + sessid := m.Cmd("aaa.user", user, "ssh").Append("key") if sessid == "" { // 创建会话 sessid = m.Cmdx("aaa.sess", "ssh", "ip", "what") m.Cmd("aaa.sess", sessid, user, "ppid", "what") } - bench := m.Cmd("aaa.sess", sessid, "bench").Append("meta") + bench := m.Cmd("aaa.sess", sessid, "bench").Append("key") if bench == "" { // 创建空间 bench = m.Cmdx("aaa.work", sessid, "ssh") } if m.Cmds("aaa.work", bench, "right", user, "remote", arg[0]) { // 执行命令 - msg := m.Find(m.Option("current_ctx", kit.Format(host["cm_target"]))).Cmd(arg).CopyTo(m) - host["cm_target"] = msg.Cap("module") + msg := m.Find(m.Option("current_ctx", kit.Format(node["cm_target"]))).Cmd(arg).CopyTo(m) + node["cm_target"] = msg.Cap("module") } else { m.Echo("no right %s %s", "remote", arg[0]) } @@ -170,17 +170,17 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", } rest := kit.Select("", names, 1) - m.Option("hostname", m.Cap("hostname")) + m.Option("nodename", m.Cap("nodename")) if names[0] == "*" { // 广播命令 - m.Confm("host", func(name string, host map[string]interface{}) { - m.Find(kit.Format(host["module"]), true).Copy(m, "option").CallBack(sync, func(sub *ctx.Message) *ctx.Message { + m.Confm("node", func(name string, node map[string]interface{}) { + m.Find(kit.Format(node["module"]), true).Copy(m, "option").CallBack(sync, func(sub *ctx.Message) *ctx.Message { return m.Copy(sub, "append").Copy(sub, "result") }, "send", "", arg) }) - } else if m.Confm("host", names[0], func(host map[string]interface{}) { // 单播命令 - m.Find(kit.Format(host["module"]), true).Copy(m, "option").CallBack(sync, func(sub *ctx.Message) *ctx.Message { + } else if m.Confm("node", names[0], func(node map[string]interface{}) { // 单播命令 + m.Find(kit.Format(node["module"]), true).Copy(m, "option").CallBack(sync, func(sub *ctx.Message) *ctx.Message { return m.Copy(sub, "append").Copy(sub, "result") }, "send", rest, arg) @@ -192,16 +192,16 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", } return }}, - "sh": &ctx.Command{Name: "sh [[host] name] cmd...", Help: "发送命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + "sh": &ctx.Command{Name: "sh [[node] name] cmd...", Help: "发送命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if len(arg) == 0 { m.Echo(m.Conf("current")) return } - if arg[0] == "host" { + if arg[0] == "node" { m.Conf("current", arg[1]) arg = arg[2:] - } else if m.Confm("host", arg[0]) != nil { + } else if m.Confm("node", arg[0]) != nil { m.Conf("current", arg[0]) arg = arg[1:] } @@ -211,16 +211,16 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", m.Copy(msg, "result") return }}, - "cp": &ctx.Command{Name: "cp [[host] name] filename", Help: "发送文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + "cp": &ctx.Command{Name: "cp [[node] name] filename", Help: "发送文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if len(arg) == 0 { m.Echo(m.Conf("current")) return } - if arg[0] == "host" { + if arg[0] == "node" { m.Conf("current", arg[1]) arg = arg[2:] - } else if m.Confm("host", arg[0]) != nil { + } else if m.Confm("node", arg[0]) != nil { m.Conf("current", arg[0]) arg = arg[1:] } diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index a2f1ff44..5298c3d9 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -142,6 +142,20 @@ func (web *WEB) HandleCmd(m *ctx.Message, key string, cmd *ctx.Command) { msg.Option("path", r.URL.Path) msg.Optionv("debug", false) + agent := r.Header.Get("User-Agent") + switch { + case strings.Contains(agent, "Macintosh"): + msg.Option("GOOS", "darwin") + default: + msg.Option("GOOS", "linux") + } + switch { + case strings.Contains(agent, "Intel"): + msg.Option("GOARCH", "386") + default: + msg.Option("GOARCH", "386") + } + msg.Option("dir_root", msg.Cap("directory")) for _, v := range r.Cookies() { msg.Option(v.Name, v.Value) @@ -553,7 +567,7 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", var result interface{} ct := res.Header.Get("Content-Type") parse := kit.Select(kit.Format(client["parse"]), m.Option("parse")) - m.Log("info", "parse: %s content: %s", parse, ct) + m.Log("info", "status %s parse: %s content: %s", res.Status, parse, ct) switch { case parse == "json" || strings.HasPrefix(ct, "application/json") || strings.HasPrefix(ct, "application/javascript"): diff --git a/src/examples/code/code.go b/src/examples/code/code.go index 06aa8794..cc2f881d 100644 --- a/src/examples/code/code.go +++ b/src/examples/code/code.go @@ -7,7 +7,7 @@ import ( "net/http" "os" "strconv" - "time" + "strings" ) var Index = &ctx.Context{Name: "code", Help: "代码中心", @@ -215,14 +215,65 @@ var Index = &ctx.Context{Name: "code", Help: "代码中心", }, Help: "组件列表"}, "upgrade": &ctx.Config{Name: "upgrade", Value: map[string]interface{}{ "file": map[string]interface{}{ + "boot_sh": "bin/boot.sh", + "bench": "bin/bench.new", "init_shy": "etc/init.shy", "common_shy": "etc/common.shy", "exit_shy": "etc/exit.shy", - "bench": "bin/bench.new", }, }, Help: "日志地址"}, }, Commands: map[string]*ctx.Command{ + "update": &ctx.Command{Name: "update", Help: "更新代码", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + return + }}, + "/upgrade/": &ctx.Command{Name: "/upgrade/", Help: "下载文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + p := m.Cmdx("nfs.path", key) + if strings.HasSuffix(key, "/bench") { + bench := m.Cmdx("nfs.path", key+"."+m.Option("GOOS")+"."+m.Option("GOARCH")) + if _, e := os.Stat(bench); e == nil { + p = bench + } + } + + m.Log("info", "upgrade %s %s", p, m.Cmdx("aaa.hash", "file", p)) + http.ServeFile(m.Optionv("response").(http.ResponseWriter), m.Optionv("request").(*http.Request), p) + return + }}, + "upgrade": &ctx.Command{Name: "upgrade system|script", Help: "服务升级", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + if len(arg) == 0 { + m.Cmdy("ctx.config", "upgrade", "file") + return + } + + if arg[0] == "system" { + arg = arg[1:] + m.Confm("upgrade", "file", func(key string, value string) { + arg = append(arg, key) + }) + } + + restart := false + for _, link := range arg { + if file := m.Conf("upgrade", []string{"file", link}); file != "" { + if m.Cmd("web.get", "dev", fmt.Sprintf("code/upgrade/%s", link), "save", file); strings.HasPrefix(file, "bin/") { + if m.Cmd("cli.system", "chmod", "u+x", file); link == "bench" { + m.Cmd("cli.system", "mv", "bin/bench", fmt.Sprintf("bin/bench_%s", m.Time("20060102_150405"))) + m.Cmd("cli.system", "mv", "bin/bench.new", "bin/bench") + } + } + restart = true + } else { + m.Cmdy("web.get", "dev", fmt.Sprintf("code/upgrade/script/%s", link), "save", fmt.Sprintf("usr/script/%s", link)) + } + } + + if restart { + m.Cmd("cli.exit", 1) + } + return + }}, + "/counter": &ctx.Command{Name: "/counter", Help: "/counter", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if len(arg) > 0 { m.Option("name", arg[0]) @@ -248,54 +299,6 @@ var Index = &ctx.Context{Name: "code", Help: "代码中心", } return }}, - "/upgrade/": &ctx.Command{Name: "/upgrade/", Help: "下载文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - r := m.Optionv("request").(*http.Request) - w := m.Optionv("response").(http.ResponseWriter) - p := m.Cmdx("nfs.path", key) - m.Log("info", "upgrade %s %s", p, m.Cmdx("aaa.hash", "file", p)) - http.ServeFile(w, r, p) - return - }}, - "upgrade": &ctx.Command{Name: "upgrade system|script", Help: "服务升级", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - if len(arg) == 0 { - m.Cmdy("ctx.config", "upgrade", "file") - return - } - - if arg[0] == "system" { - m.Cmd("cli.source", m.Conf("exit.shy")) - - m.Confm("upgrade", "file", func(key string, value string) { - m.Cmd("web.get", "dev", fmt.Sprintf("code/upgrade/%s", key), "save", value) - }) - - m.Cmd("cli.system", "chmod", "u+x", "bin/bench.new") - m.Cmd("cli.system", "mv", "bin/bench", fmt.Sprintf("bin/bench_%s", m.Time("20060102_150405"))) - m.Cmd("cli.system", "mv", "bin/bench.new", "bin/bench") - go func() { - time.Sleep(time.Second * 3) - os.Exit(1) - }() - return - } - - if file := m.Conf("upgrade", []string{"file", arg[0]}); file != "" { - m.Cmd("web.get", "dev", fmt.Sprintf("code/upgrade/%s", arg[0]), "save", file) - if arg[0] == "bench" { - m.Cmd("cli.system", "chmod", "u+x", "bin/bench.new") - m.Cmd("cli.system", "mv", "bin/bench", fmt.Sprintf("bin/bench_%s", m.Time("20060102_150405"))) - m.Cmd("cli.system", "mv", "bin/bench.new", "bin/bench") - } - go func() { - time.Sleep(time.Second * 3) - os.Exit(1) - }() - return - } - - m.Cmdy("web.get", "dev", fmt.Sprintf("code/upgrade/script/%s", arg[0]), "save", fmt.Sprintf("usr/script/%s", arg[0]), arg[1:]) - return - }}, "/consul": &ctx.Command{Name: "/consul", Help: "下载文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { m.Append("hostport", m.Cmdx("ssh.config", "hostport")) return diff --git a/usr/favicon.ico b/usr/favicon.ico new file mode 100644 index 00000000..08d3924d Binary files /dev/null and b/usr/favicon.ico differ