├── .gitattributes ├── .gitignore ├── LICENSE ├── Makefile ├── README.MD ├── cmd ├── agent │ └── main.go ├── relaypeer │ └── relaypeer.go ├── server │ └── main.go └── test │ └── daemon.go ├── config.json ├── config.yaml ├── doc ├── README.md ├── features-zh-CN.md ├── pnet.md ├── v0.1.md └── 目录结构.md ├── go.mod ├── go.sum ├── internal ├── cmd │ └── cmd.go ├── consts │ ├── consts.go │ └── error_code.go ├── controller │ ├── agent.go │ ├── app.go │ ├── auth.go │ ├── check.go │ ├── check_tpl.go │ ├── download_file.go │ ├── middleware.go │ ├── plugin.go │ ├── pmanager.go │ ├── script.go │ ├── script_task.go │ ├── task.go │ ├── task_cron.go │ ├── task_preset.go │ ├── user.go │ └── vm.go ├── model │ ├── agent_info.go │ ├── download_file.go │ ├── entity │ │ ├── agent_info.go │ │ ├── app.go │ │ ├── check_item.go │ │ ├── check_tpl.go │ │ ├── check_tpl_detail.go │ │ ├── cron_task.go │ │ ├── plugin.go │ │ ├── script.go │ │ ├── task.go │ │ ├── task_preset.go │ │ ├── user.go │ │ └── vm.go │ ├── fileinfo.go │ ├── peer.go │ └── script.go ├── packed │ └── packed.go ├── peer │ ├── handlermsg.go │ ├── osp_peer.go │ └── peer.go └── service │ ├── app.go │ ├── auth.go │ ├── checkitem.go │ ├── checktpl.go │ ├── internal │ ├── dao │ │ ├── agent_info.go │ │ ├── app.go │ │ ├── check_item.go │ │ ├── check_tpl.go │ │ ├── check_tpl_detail.go │ │ ├── cron_task.go │ │ ├── internal │ │ │ ├── agent_info.go │ │ │ ├── app.go │ │ │ ├── check_item.go │ │ │ ├── check_tpl.go │ │ │ ├── check_tpl_detail.go │ │ │ ├── cron_task.go │ │ │ ├── plugin.go │ │ │ ├── script.go │ │ │ ├── task.go │ │ │ ├── task_preset.go │ │ │ ├── user.go │ │ │ └── vm.go │ │ ├── plugin.go │ │ ├── script.go │ │ ├── task.go │ │ ├── task_preset.go │ │ ├── user.go │ │ └── vm.go │ └── do │ │ ├── agent_info.go │ │ ├── app.go │ │ ├── check_item.go │ │ ├── check_tpl.go │ │ ├── check_tpl_detail.go │ │ ├── cron_task.go │ │ ├── plugin.go │ │ ├── script.go │ │ ├── task.go │ │ ├── task_preset.go │ │ ├── user.go │ │ └── vm.go │ ├── plugin.go │ ├── script.go │ ├── task.go │ ├── task_cron.go │ ├── task_preset.go │ ├── user.go │ └── vm.go ├── manifest ├── config │ └── config.yaml ├── deploy │ └── kustomize │ │ ├── base │ │ ├── deployment.yaml │ │ ├── kustomization.yaml │ │ └── service.yaml │ │ └── overlays │ │ └── develop │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ └── kustomization.yaml └── docker │ ├── Dockerfile │ └── docker.sh ├── pkg ├── agent │ ├── action │ │ ├── agent_manager.go │ │ ├── agent_manager_control.go │ │ ├── agent_manager_control_unix.go │ │ ├── agent_manager_control_windows.go │ │ ├── download_file.go │ │ ├── file_disk.go │ │ └── runner.go │ ├── agent.go │ ├── agent_filemanager.go │ ├── cmd.go │ ├── cmdrunner │ │ ├── cmd_runner.go │ │ └── script_runner.go │ ├── config │ │ └── config.go │ ├── handlermsg.go │ ├── script │ │ ├── agent_plugin.go │ │ ├── cmd │ │ │ ├── build_cmd_unix.go │ │ │ └── build_cmd_windows.go │ │ ├── content_script.go │ │ ├── content_script_test.go │ │ ├── ext_unix.go │ │ ├── ext_windows.go │ │ ├── generic_script.go │ │ ├── generic_script_test.go │ │ ├── job_script.go │ │ ├── name_script.go │ │ ├── pack_script.go │ │ ├── pathenv │ │ │ └── pathenv.go │ │ ├── plugin.go │ │ ├── script_interface.go │ │ └── url_script.go │ ├── task │ │ ├── async_task_service.go │ │ ├── service_interface.go │ │ ├── task.go │ │ ├── task_manager.go │ │ └── task_manager_interface.go │ └── test │ │ ├── test.go │ │ ├── test2.go │ │ └── test3.go ├── api │ └── v1 │ │ ├── agent_info.go │ │ ├── app.go │ │ ├── base.go │ │ ├── check.go │ │ ├── download_file.go │ │ ├── fileinfo.go │ │ ├── plugin.go │ │ ├── pmanager.go │ │ ├── script.go │ │ ├── script_task.go │ │ ├── task.go │ │ ├── user.go │ │ └── vm.go ├── consistenthash │ └── consistenhash.go ├── daemon │ ├── attr_unix.go │ ├── attr_windows.go │ ├── daemon.go │ └── test │ │ └── main.go ├── dcron │ ├── dcron.go │ ├── driver.go │ ├── job_warpper.go │ ├── node_pool.go │ └── option.go ├── errors │ └── error.go ├── leveldb │ └── leveldb.go ├── logger │ ├── logger.go │ └── logger_test.go ├── message │ ├── jsonc.go │ └── message.go ├── proto │ ├── ops_agent_plugin.pb.go │ └── ops_agent_plugin.proto ├── schema │ ├── message.pb.go │ ├── message.proto │ └── messagepb_test.go ├── stat │ └── stat.go ├── system │ ├── cmd_runner.go │ ├── exec_cmd_runner.go │ ├── exec_cmd_runner_unix.go │ ├── exec_cmd_runner_windows.go │ ├── exec_error.go │ ├── exec_process.go │ ├── exec_process_unix.go │ └── exec_process_windows.go └── util │ ├── codec.go │ ├── mapreduce.go │ └── signature.go ├── public ├── index.html ├── script │ └── test.sh ├── umi.css └── umi.js ├── resource ├── i18n │ └── .gitkeep ├── images │ ├── p1.png │ ├── p2.png │ ├── p3.png │ ├── p4.png │ └── pnet1.png ├── public │ ├── html │ │ └── .gitkeep │ ├── plugin │ │ └── .gitkeep │ └── resource │ │ ├── css │ │ └── .gitkeep │ │ ├── image │ │ └── .gitkeep │ │ └── js │ │ └── .gitkeep └── template │ └── .gitkeep ├── scripts └── ops.sql ├── swagger ├── index.html └── redoc.standalone.js └── test ├── peer.go └── py ├── apps.py ├── ops.py ├── peernode.py ├── script.py └── task_preset.py /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-language=GO -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | config.yaml 3 | agent/cmd/agent 4 | osp 5 | relaypeer/relaypeer 6 | .buildpath 7 | .hgignore.swp 8 | .project 9 | .orig 10 | .swp 11 | .idea/ 12 | .settings/ 13 | .vscode/ 14 | vendor/ 15 | composer.lock 16 | gitpush.sh 17 | bin/ 18 | cbuild 19 | **/.DS_Store 20 | .vscode/ 21 | .test/ 22 | main 23 | output/ 24 | manifest/output/ 25 | temp/ 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ROOT_DIR = $(shell pwd) 2 | NAMESPACE = "default" 3 | DEPLOY_NAME = "template-single" 4 | DOCKER_NAME = "template-single" 5 | 6 | 7 | .PHONY: agent 8 | agent: 9 | go build -o bin/agent cmd/agent/main.go 10 | 11 | .PHONY: apiserver 12 | apiserver: 13 | go build -o bin/apiserver cmd/server/main.go 14 | 15 | 16 | .PHONY: build 17 | build: agent apiserver 18 | 19 | # Install/Update to the latest CLI tool. 20 | .PHONY: cli 21 | cli: 22 | @set -e; \ 23 | wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(shell go env GOOS)_$(shell go env GOARCH) && \ 24 | chmod +x gf && \ 25 | ./gf install -y && \ 26 | rm ./gf 27 | 28 | 29 | # Check and install CLI tool. 30 | .PHONY: cli.install 31 | cli.install: 32 | @set -e; \ 33 | gf -v > /dev/null 2>&1 || if [[ "$?" -ne "0" ]]; then \ 34 | echo "GoFame CLI is not installed, start proceeding auto installation..."; \ 35 | make cli; \ 36 | fi; 37 | 38 | 39 | # Generate Go files for DAO/DO/Entity. 40 | .PHONY: dao 41 | dao: cli.install 42 | @gf gen dao 43 | 44 | 45 | .PHONY: pb 46 | pb: 47 | protoc -I pkg/proto/ pkg/proto/*.proto --go_out=plugins=grpc:pkg/proto/ 48 | 49 | 50 | # Build image, deploy image and yaml to current kubectl environment and make port forward to local machine. 51 | .PHONY: start 52 | start: 53 | @set -e; \ 54 | make image; \ 55 | make deploy; \ 56 | make port; 57 | 58 | # Build docker image. 59 | .PHONY: image 60 | image: cli.install 61 | $(eval _TAG = $(shell git log -1 --format="%cd.%h" --date=format:"%Y%m%d%H%M%S")) 62 | ifneq (, $(shell git status --porcelain 2>/dev/null)) 63 | $(eval _TAG = $(_TAG).dirty) 64 | endif 65 | $(eval _TAG = $(if ${TAG}, ${TAG}, $(_TAG))) 66 | $(eval _PUSH = $(if ${PUSH}, ${PUSH}, )) 67 | @gf docker -p -b "-a amd64 -s linux -p temp" -t $(DOCKER_NAME):${_TAG}; 68 | 69 | 70 | # Build docker image and automatically push to docker repo. 71 | .PHONY: image.push 72 | image.push: 73 | @make image PUSH=-p; 74 | 75 | 76 | # Deploy image and yaml to current kubectl environment. 77 | .PHONY: deploy 78 | deploy: 79 | $(eval _ENV = $(if ${ENV}, ${ENV}, develop)) 80 | 81 | @set -e; \ 82 | mkdir -p $(ROOT_DIR)/temp/kustomize;\ 83 | cd $(ROOT_DIR)/manifest/deploy/kustomize/overlays/${_ENV};\ 84 | kustomize build > $(ROOT_DIR)/temp/kustomize.yaml;\ 85 | kubectl apply -f $(ROOT_DIR)/temp/kustomize.yaml; \ 86 | kubectl patch -n $(NAMESPACE) deployment/$(DEPLOY_NAME) -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"$(shell date +%s)\"}}}}}"; 87 | 88 | 89 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Go-OPS 2 | 3 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 4 | 5 | Go-ops是面向云平台系统, 基于 PaaS 技术支持客户实现 DevOps 解决方案的平台。提供完善作业管理、配置管理、定期调度、健康巡检等模块,助力运维人员快速、低成本、自动化的管理配置运维系统。 6 | 7 | 8 | 9 | ## 功能 10 | - 节点管理 11 | - 节点连接/断开 12 | - 节点健康状态 13 | - 节点自我升级 14 | - 资源管理 15 | - 脚本资源 16 | - 巡检项 17 | - 巡检模板 18 | - 文件资源 19 | - 插件资源 20 | - 任务管理 21 | - 脚本任务 22 | - 文件分发 23 | - 巡检任务 24 | - 预设任务 25 | - 定时任务 26 | - agent管理 27 | - 作业管理 28 | - 分批作业 29 | - 作业编排 30 | - APP(对接方)管理 31 | - 权限控制 32 | - 用户权限 33 | - 对接方权限 34 | - 远程连接 35 | - ssh协议 36 | - vnc协议 37 | 38 | 39 | ## 构建项目 40 | 41 | - make 42 | 43 | > make build 44 | 45 | 46 | 47 | - 配置文件说明 48 | - config.json agent配置文件 49 | ```json 50 | { 51 | "port":13333, // agent 监听的端口号 52 | "bootlist":["tcp://127.0.0.1:9999"] // 引导网络地址 53 | } 54 | ``` 55 | - config.yaml apiserver配置文件 56 | 57 | ```yaml 58 | 59 | database: 60 | default: 61 | link: "mysql:root:root@tcp(127.0.0.1:3306)/ops" # 数据库连接串 62 | debug: "true" # 是否开启调试模式 63 | 64 | server: 65 | ServerRoot: "public" # 静态资源文件目录 66 | address: ":8199" # api 监听端口 67 | openapiPath: "/api.json" # openapi 接口文件 68 | 69 | peer: 70 | port: 9999 # 节点监听端口号 71 | boots: # 加入的网络节点列表 72 | - addr: "tcp://xxxx" # 引导节点地址1 73 | - addr: "tcp://xx11122" # 引导节点地址2 74 | ``` 75 | 76 | 77 | ## 运行项目 78 | 79 | > 如果是第一次运行需要在数据库中创建数据库,并导入scripts/ops.sql 这个文件的表结构信息 80 | 81 | - apiserver 82 | > bin/apiserver 83 | 84 | 或者 85 | > go run cmd/server/main.go 86 | 87 | - agent 88 | > bin/agent 89 | 90 | 或者 91 | > agent: go run cmd/agent/main.go 92 | 93 | 94 | ## 前端 95 | 96 | https://github.com/i4de/opsApp 97 | 98 | 99 | ## 文档 100 | 101 | https://www.yuque.com/lewisxw/goops -------------------------------------------------------------------------------- /cmd/agent/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go-ops/pkg/agent" 5 | "log" 6 | ) 7 | 8 | func main() { 9 | err := agent.Main() 10 | if err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /cmd/relaypeer/relaypeer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "go-ops/internal/peer" 7 | "go-ops/pkg/agent" 8 | "log" 9 | "net" 10 | "os" 11 | "os/signal" 12 | "syscall" 13 | 14 | "github.com/google/uuid" 15 | "github.com/luxingwen/pnet/config" 16 | "github.com/shirou/gopsutil/v3/host" 17 | ) 18 | 19 | func InitSignal() { 20 | sig := make(chan os.Signal, 2) 21 | signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) 22 | 23 | for { 24 | s := <-sig 25 | fmt.Println("Got signal:", s) 26 | os.Exit(1) 27 | } 28 | 29 | } 30 | 31 | func getClientIp() string { 32 | addrs, err := net.InterfaceAddrs() 33 | 34 | if err != nil { 35 | return "127.0.0.1" 36 | } 37 | 38 | for _, address := range addrs { 39 | // 检查ip地址判断是否回环地址 40 | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 41 | if ipnet.IP.To4() != nil { 42 | return ipnet.IP.String() 43 | } 44 | 45 | } 46 | } 47 | 48 | return "127.0.0.1" 49 | } 50 | 51 | func main() { 52 | 53 | fg := flag.NewFlagSet("relay-peer", flag.ContinueOnError) 54 | 55 | var addr string 56 | var port uint64 57 | var name string 58 | var id string 59 | var h bool 60 | fg.StringVar(&addr, "addr", "", "-addr") 61 | fg.Uint64Var(&port, "port", 12333, "-port port") 62 | fg.StringVar(&name, "name", "", "-name name") 63 | fg.StringVar(&id, "id", "", "-id name") 64 | fg.BoolVar(&h, "h", false, "-h help") 65 | 66 | err := fg.Parse(os.Args[1:]) 67 | if err != nil { 68 | log.Fatal(err) 69 | } 70 | 71 | if h { 72 | fg.Usage() 73 | return 74 | } 75 | 76 | ospAgent := agent.NewOspAgent("./") 77 | 78 | conf := &config.Config{} 79 | 80 | if name == "" { 81 | name, err = os.Hostname() 82 | if err != nil { 83 | log.Fatal(err) 84 | } 85 | name += "@relay" 86 | } 87 | 88 | if id == "" { 89 | hid, err := host.HostID() 90 | if err != nil { 91 | id = uuid.New().String() 92 | } else { 93 | id = hid 94 | } 95 | } 96 | 97 | id = id + "@relay" 98 | 99 | conf.Name = name 100 | conf.Port = uint16(port) 101 | 102 | p, err := peer.NewPnet(id, conf, ospAgent.HandlerFunc) 103 | if err != nil { 104 | fmt.Println("new peer err:") 105 | return 106 | } 107 | 108 | err = p.Start() 109 | if err != nil { 110 | log.Fatal(err) 111 | } 112 | 113 | localaddr := fmt.Sprintf("tcp://%s:%d", getClientIp(), port) 114 | fmt.Println("relay start addr:", localaddr) 115 | 116 | if addr != "" { 117 | fmt.Println("join add:", addr) 118 | _, err := p.Join(addr) 119 | if err != nil { 120 | log.Fatal("join:", err) 121 | } 122 | } 123 | 124 | InitSignal() 125 | 126 | } 127 | -------------------------------------------------------------------------------- /cmd/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go-ops/internal/cmd" 5 | _ "go-ops/internal/packed" 6 | "go-ops/internal/peer" 7 | 8 | "github.com/gogf/gf/v2/os/glog" 9 | 10 | "github.com/luxingwen/pnet/config" 11 | 12 | "github.com/gogf/gf/v2/frame/g" 13 | 14 | "github.com/gogf/gf/v2/os/gctx" 15 | "github.com/google/uuid" 16 | ) 17 | 18 | func main() { 19 | 20 | log := glog.DefaultLogger() 21 | var ctx = gctx.New() 22 | var port uint16 = 9999 23 | 24 | portvar, err := g.Cfg().Get(ctx, "peer.port") 25 | if err != nil { 26 | log.Warning(ctx, "没有配置节点端口,将使用默认端口:", port) 27 | } else { 28 | port = portvar.Uint16() 29 | } 30 | 31 | var addrs []string 32 | 33 | boots, err := g.Cfg().Get(ctx, "peer.boots") 34 | if err != nil { 35 | log.Warning(ctx, "获取引导节点失败,err:", err) 36 | } else { 37 | for _, item := range boots.Array() { 38 | dataval := item.(map[string]interface{}) 39 | addrs = append(addrs, dataval["addr"].(string)) 40 | } 41 | } 42 | 43 | id := uuid.New().String() 44 | 45 | id += "@ops-apiserver" 46 | conf := &config.Config{} 47 | conf.Port = uint16(port) 48 | conf.Name = "ops-apiserver" 49 | 50 | err = peer.InitOspPeer(id, conf) 51 | if err != nil { 52 | log.Fatal(ctx, err) 53 | } 54 | 55 | for _, addr := range addrs { 56 | _, err = peer.GetOspPeer().Join(addr) 57 | if err != nil { 58 | log.Warning(ctx, "join addr:", addr, " err: ", err) 59 | } 60 | } 61 | 62 | cmd.Main.Run(gctx.New()) 63 | } 64 | -------------------------------------------------------------------------------- /cmd/test/daemon.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go-ops/pkg/daemon" 6 | "os" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | dae := daemon.NewDaemon() 12 | dae.Start() 13 | 14 | fmt.Println("pid : ", os.Getegid()) 15 | 16 | time.Sleep(time.Second) 17 | fmt.Println("end->") 18 | } 19 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port":13333, 3 | "bootlist":["tcp://127.0.0.1:9999"] 4 | } -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | gfcli: 2 | gen: 3 | dao: 4 | - link: "mysql:root:root@tcp(192.168.1.4:3306)/osp" 5 | jsonCase: "CamelLower" 6 | path: "./internal" 7 | 8 | database: 9 | default: 10 | link: "mysql:root:root@tcp(192.168.1.2:3306)/osp" 11 | debug: "true" 12 | 13 | server: 14 | ServerRoot: "public" 15 | address: ":8199" 16 | openapiPath: "/api.json" 17 | 18 | peer: 19 | port: 9999 # 节点监听端口号 20 | boots: # 加入的网络节点列表 21 | - addr: "tcp:xxxx" 22 | - addr: "tcp:xx11122" -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Go-ops doc 2 | -------------------------------------------------------------------------------- /doc/features-zh-CN.md: -------------------------------------------------------------------------------- 1 | # 详细功能描述 2 | 3 | 4 | ## 1. 节点 5 | 6 | ### 1.0 节点管理 7 | * [x] 连接节点 8 | * [x] 断开节点 9 | * [ ] 自动重连 10 | * [x] 节点列表 11 | * [ ] 给节点打标签 12 | 13 | ### 1.1 节点状态 14 | * [x] cpu 15 | * [x] 内存 16 | * [x] 硬盘使用情况 17 | * [x] 网卡信息 18 | 19 | ### 1.2 节点文件操作 20 | * [ ] 查看节点文件夹 21 | * [ ] 在节点上创建文件夹 22 | * [ ] 删除文件 23 | * [ ] 移动文件 24 | * [ ] 上传文件 25 | * [ ] 下载文件 26 | 27 | 28 | 29 | ## 2. 资源管理 30 | 31 | ### 2.1 脚本资源 32 | * [ ] 创建脚本 33 | * [ ] 删除脚本 34 | * [ ] 编辑脚本 35 | * [ ] 克隆(复制别人的)脚本 36 | * [ ] 公共脚本库 37 | * [ ] 用户脚本库 38 | 39 | ### 2.2 文件资源 40 | * [ ] 创建文件空间 41 | * [ ] 修改文件空间 42 | * [ ] 删除文件空间 43 | * [ ] 文件上传 44 | * [ ] 文件下载 45 | * [ ] 文件锁 46 | * [ ] 文件删除 47 | 48 | ### 2.3 巡检项 49 | * [ ] 创建巡检项 50 | * [ ] 删除巡检项 51 | * [ ] 编辑巡检项 52 | 53 | ### 2.4 巡检模板 54 | * [ ] 创建巡检模板 55 | * [ ] 删除巡检模板 56 | * [ ] 编辑巡检模板 57 | 58 | 59 | 60 | ### 2.5 插件资源 61 | * [ ] 添加插件资源 62 | * [ ] 编辑插件 63 | * [ ] 删除插件 64 | 65 | ### 2.6 agent资源管理 66 | * [ ] 增加默认agent 67 | * [ ] 更新默认agent 68 | * [ ] 默认agent-包管理 69 | * [ ] 删除agent资源 70 | 71 | 72 | 73 | 74 | 75 | ## 3. 脚本任务 76 | 77 | ### 3.1 脚本任务执行支持 78 | * [x] 指定特定用户运行(只支持linux) 79 | * [x] 脚本运行的工作目录 80 | * [x] 脚本运行的超时时间 81 | * [x] 脚本参数 82 | * [x] 自定义解释器 83 | * [x] 脚本输入(脚本运行过程中需要用户的输入) 84 | * [x] 中断脚本执行(脚本在运行过程中,可以中断取消) 85 | 86 | ### 3.2 脚本任务执行方式 87 | * [x] 命令下发 (执行简单的命令) 88 | * [x] 脚本内容下发 (执行复杂脚本) 89 | * [x] 执行本地脚本 (脚本存放在本地) 90 | * [x] 执行URL脚本 (从URL下载脚本到本地执行) 91 | * [ ] 插件任务 (可以通过插件方式执行任务) 92 | 93 | 94 | ## 4. 文件分发任务 95 | * [x] 通过给定文件URL下载地址分发到指定节点(文件下载) 96 | * [ ] 通过文件流方式推送文件到指定节点(文件下载) 97 | 98 | 99 | ## 5.Agent管理 100 | 101 | ### 5.1 节点agent管理 102 | * [x] agent安装 103 | * [x] agent卸载 104 | * [x] agent启动 105 | * [x] agent停止 106 | * [ ] 查看agent状态 107 | 108 | 109 | 110 | 111 | 112 | ## 6. 调用方(APP)管理 113 | * [x] 新增调用方 114 | * [x] 更新调用方 115 | * [x] 删除调用方 116 | * [x] 查询调用方 117 | 118 | ## 7. 用户管理 119 | * [ ] 新增用户 120 | * [ ] 更新用户 121 | * [ ] 删除用户 122 | * [ ] 用户角色 123 | 124 | ## 8. 权限控制 125 | * [ ] 调用方权限控制 126 | * [ ] 用户权限控制 127 | 128 | 129 | ## 9. 文件服务器 130 | * [ ] 支持本地存储,s3协议的文件服务器存储 131 | * [ ] 文件上传 (上传文件到文件服务器) 132 | * [ ] 文件锁 (被引用文件不可被删除,但是可以被更新) 133 | * [ ] 文件删除 (从文件服务器删除文件) 134 | * [ ] 获取文件列表信息 (获取文件服务器的列表信息) 135 | 136 | 137 | ## 10. 任务管理 138 | 139 | ### 10.1 创建、编辑任务 140 | * [ ] 创建、编辑脚本任务 141 | * [ ] 创建、编辑巡检任务 142 | * [ ] 创建、编辑文件分发任务 143 | * [ ] 创建、编辑定时任务 144 | * [ ] 创建、编辑预设任务 145 | 146 | ### 10.2 任务记录 147 | * [ ] 任务运行记录列表 148 | * [ ] 任务运行记录详情查看 149 | * [ ] 取消任务 150 | 151 | ### 10.3 预设任务 152 | * [ ] 预设任务列表 153 | * [ ] 预设任务详情 154 | * [ ] 预设任务删除 155 | * [ ] 运行预设任务 156 | 157 | ### 10.4 定时任务 158 | * [ ] 定时任务列表 159 | * [ ] 定时任务详情 160 | * [ ] 定时任务删除 161 | * [ ] 启动定时任务 162 | * [ ] 停止定时任务 163 | 164 | 165 | ## 11. 作业管理 166 | 167 | ### 11.1 批次作业 168 | * [ ] 任务分批次运行 169 | 170 | ### 11.2 作业编排 171 | * [ ] 任务通过作业编排方式运行 172 | 173 | ## 12. 远程连接 174 | 175 | ### 12.1 ssh连接 176 | ### 12.2 vnc连接 -------------------------------------------------------------------------------- /doc/pnet.md: -------------------------------------------------------------------------------- 1 | 2 | # pnet网络 3 | 4 | 如果可以的话,节点与节点之间,可以任意互相连接,每个节点它只维护与它相邻节点的连接信息。所以你可以无限的扩展,无限的连接更多的节点。但是通常不建议你那么做,因为这样会使得消息经过的节点太多。 5 | 6 | 简单画了几个图帮助你理解。 7 | 8 | ![](resource/images/pnet1.png) 9 | 10 | 11 | ## 部署架构 12 | 13 | 这里简单介绍几种整个系统的部署架构, 而不是go-ops这个节点的部署。 14 | 15 | - 单节点, 单可用区, 节点直连go-ops 16 | 17 | ![](resource/images/p1.png) 18 | 19 | - 单节点, 单可用区, 节点通过节点接入 20 | 21 | ![](resource/images/p2.png) 22 | 23 | - 单节点, 单可用区, 节点通过超级节点接入 24 | 25 | ![](resource/images/p3.png) 26 | 27 | 28 | - 多节点, 多可用区, 高可用 29 | 30 | ![](resource/images/p4.png) -------------------------------------------------------------------------------- /doc/v0.1.md: -------------------------------------------------------------------------------- 1 | # 0.1 版本需要实现功能 2 | 3 | ## 1. pnet 需要实现的功能 4 | 5 | ## 2. agent需要实现的功能 6 | 7 | ### 2.1 脚本任务执行支持 8 | * [x] 指定特定用户运行(只支持linux) 9 | * [x] 脚本运行的工作目录 10 | * [x] 脚本运行的超时时间 11 | * [x] 脚本参数 12 | * [x] 自定义解释器 13 | * [x] 脚本输入(脚本运行过程中需要用户的输入) 14 | * [x] 中断脚本执行(脚本在运行过程中,可以中断取消) 15 | 16 | ### 2.2 脚本任务执行方式 17 | * [x] 命令下发 (执行简单的命令) 18 | * [x] 脚本内容下发 (执行复杂脚本) 19 | * [x] 执行本地脚本 (脚本存放在本地) 20 | * [x] 执行URL脚本 (从URL下载脚本到本地执行) 21 | 22 | 23 | ## 3.管理节点apiserver需要实现的功能 24 | 25 | ### 3.1 脚本任务 26 | * [x] 创建脚本任务 27 | * [ ] 查看脚本任务记录 28 | * [ ] 查看脚本任务记录详情 29 | 30 | ### 3.2 用户管理 31 | * [x] 用户登录 32 | * [x] 用户token认证 33 | * [x] 用户token续期 34 | 35 | ### 3.3 节点管理 36 | * [ ] 查看节点列表 37 | -------------------------------------------------------------------------------- /doc/目录结构.md: -------------------------------------------------------------------------------- 1 | # 目录结构介绍 2 | 3 | -------------------------------------------------------------------------------- /internal/cmd/cmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/gogf/gf/v2/protocol/goai" 7 | 8 | "go-ops/internal/consts" 9 | "go-ops/internal/controller" 10 | 11 | "github.com/gogf/gf/v2/frame/g" 12 | "github.com/gogf/gf/v2/net/ghttp" 13 | "github.com/gogf/gf/v2/os/gcmd" 14 | ) 15 | 16 | func MiddlewareCORS(r *ghttp.Request) { 17 | r.Response.CORSDefault() 18 | r.Middleware.Next() 19 | } 20 | 21 | var ( 22 | Main = gcmd.Command{ 23 | Name: "main", 24 | Usage: "main", 25 | Brief: "start http server", 26 | Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { 27 | s := g.Server() 28 | 29 | s.Group("/", func(group *ghttp.RouterGroup) { 30 | group.Middleware(MiddlewareCORS) 31 | 32 | // group.Middleware(controller.MiddlewareGetApp) 33 | group.Middleware(ghttp.MiddlewareHandlerResponse) 34 | 35 | group.Bind( 36 | controller.Auth, 37 | ) 38 | group.Group("/", func(group *ghttp.RouterGroup) { 39 | // 打开这里使用认证功能 40 | group.Middleware(controller.AuthUser) 41 | group.Bind( 42 | controller.ScritptTask, 43 | controller.PeerManagaer, 44 | controller.DownloadFileTask, 45 | controller.App, 46 | controller.Task, 47 | controller.Script, 48 | controller.Agent, 49 | controller.CheckItem, 50 | controller.TaskPreset, 51 | controller.TaskCron, 52 | controller.Plugin, 53 | controller.VM, 54 | controller.User, 55 | ) 56 | }) 57 | 58 | }) 59 | 60 | s.SetIndexFolder(true) 61 | s.AddSearchPath("public") 62 | s.AddSearchPath("swagger") 63 | s.AddStaticPath("/public", "public") 64 | s.AddStaticPath("/swagger", "swagger") 65 | enhanceOpenAPIDoc(s) 66 | s.Run() 67 | return nil 68 | }, 69 | } 70 | ) 71 | 72 | func enhanceOpenAPIDoc(s *ghttp.Server) { 73 | 74 | openapi := s.GetOpenApi() 75 | openapi.Config.CommonResponse = ghttp.DefaultHandlerResponse{} 76 | openapi.Config.CommonResponseDataField = `Data` 77 | 78 | // API description. 79 | openapi.Info = goai.Info{ 80 | Title: consts.OpenAPITitle, 81 | Description: consts.OpenAPIDescription + consts.OpenAPISign, 82 | Contact: &goai.Contact{ 83 | Name: "LUXINGWEN", 84 | URL: "https://github.com/luxingwen", 85 | }, 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /internal/consts/consts.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | CheckItemTypeScript = "script" 5 | 6 | OpenAPITitle = `Go-ops Server` 7 | OpenAPIDescription = `这是go-ops server的swagger文档. Enjoy 💖 ` 8 | 9 | OpenAPISign = `

请求头

10 |
11 | 	{
12 | 		"GO-OPS-X-APPID":"你的appid",
13 | 		"GO-OPS-X-SIGNATURE":"签名值",
14 | 		"GO-OPS-X-TIMESTAMP":"时间戳",
15 | 		"GO-OPS-X-NONCE":"请求唯一id"
16 | 	}
17 | 	
18 |

签名

19 |

使用sha1作为签名算法,seckey作为签名使用key,依次把apikey、nonce、timestame、body 写入签名内容中,最后对签名结果进行base64转码

20 | Golang 21 |
22 | func GetSign(apikey string, seckey string, nonce, timestamp string, body []byte) (r string) {
23 | 	key := []byte(seckey)
24 | 	mac := hmac.New(sha1.New, key)
25 | 	mac.Write([]byte(apikey))
26 | 	mac.Write([]byte(nonce))
27 | 	mac.Write([]byte(timestamp))
28 | 	mac.Write(body)
29 | 	r = base64.StdEncoding.EncodeToString(mac.Sum(nil))
30 | 	return
31 | }
32 | 					
33 | ` 34 | ) 35 | -------------------------------------------------------------------------------- /internal/consts/error_code.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | API_CODE_INVALID_APPID = 1001 // 无效的APPID 5 | 6 | API_CODE_NODE_NOT_FOUND = 2001 // 节点不存在 7 | 8 | API_CODE_NODE_CONNECT_ERR = 2001 // 连接节点失败 9 | 10 | API_CODE_NODE_NOT_RUN = 2003 // 节点没有在运行 11 | ) 12 | -------------------------------------------------------------------------------- /internal/controller/agent.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | v1 "go-ops/pkg/api/v1" 6 | ) 7 | 8 | var Agent *agent = new(agent) 9 | 10 | type agent struct{} 11 | 12 | func (self *agent) Create(ctx context.Context, req *v1.AddAgentReq) (res *v1.AgentInfoRes, err error) { 13 | return 14 | } 15 | 16 | func (self *agent) Update(ctx context.Context, req *v1.UpdateAgentReq) (res *v1.AgentInfoRes, err error) { 17 | return 18 | } 19 | 20 | func (self *agent) Query(ctx context.Context, req *v1.QueryAgentStatusReq) (res *v1.QueryAgentStatusRes, err error) { 21 | return 22 | } 23 | -------------------------------------------------------------------------------- /internal/controller/app.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | ) 8 | 9 | var App *app = new(app) 10 | 11 | type app struct{} 12 | 13 | func (self *app) Create(ctx context.Context, req *v1.AddAppReq) (res *v1.AddAppRes, err error) { 14 | return service.App().Create(ctx, req) 15 | } 16 | 17 | func (self *app) Update(ctx context.Context, req *v1.UpdateAppReq) (res *v1.AddAppRes, err error) { 18 | return service.App().Update(ctx, req) 19 | } 20 | 21 | func (self *app) Query(ctx context.Context, req *v1.QueryAppReq) (res *v1.QueryAppRes, err error) { 22 | return service.App().Query(ctx, req) 23 | } 24 | 25 | func (self *app) SingleQuery(ctx context.Context, req *v1.QuerySingleAppReq) (res *v1.AddAppRes, err error) { 26 | return service.App().SingleQuery(ctx, req) 27 | } 28 | 29 | func (self *app) Delete(ctx context.Context, req *v1.DeleteAppReq) (res v1.DeleteRes, err error) { 30 | err = service.App().Delete(ctx, req) 31 | if err != nil { 32 | res = v1.DeleteRes("删除失败") 33 | return 34 | } 35 | res = v1.DeleteRes("删除成功") 36 | return 37 | } 38 | -------------------------------------------------------------------------------- /internal/controller/auth.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | ) 8 | 9 | type authController struct{} 10 | 11 | var Auth = authController{} 12 | 13 | func (c *authController) Login(ctx context.Context, req *v1.AuthLoginReq) (res *v1.AuthLoginRes, err error) { 14 | res = &v1.AuthLoginRes{} 15 | res.Token, res.Expire = service.Auth().LoginHandler(ctx) 16 | return 17 | } 18 | 19 | func (c *authController) RefreshToken(ctx context.Context, req *v1.AuthRefreshTokenReq) (res *v1.AuthRefreshTokenRes, err error) { 20 | res = &v1.AuthRefreshTokenRes{} 21 | res.Token, res.Expire = service.Auth().RefreshHandler(ctx) 22 | return 23 | } 24 | 25 | func (c *authController) Logout(ctx context.Context, req *v1.AuthLogoutReq) (res *v1.AuthLogoutRes, err error) { 26 | service.Auth().LogoutHandler(ctx) 27 | return 28 | } 29 | -------------------------------------------------------------------------------- /internal/controller/check.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | 8 | "github.com/gogf/gf/v2/os/glog" 9 | ) 10 | 11 | var CheckItem *checkitem = new(checkitem) 12 | 13 | type checkitem struct{} 14 | 15 | func (self *checkitem) Create(ctx context.Context, req *v1.AddCheckItemReq) (res *v1.CheckItemRes, err error) { 16 | res, err = service.Checkitem().Create(ctx, req) 17 | if err != nil { 18 | glog.Errorf(ctx, "create checkitem err:%v", err) 19 | return 20 | } 21 | return 22 | } 23 | 24 | func (self *checkitem) Update(ctx context.Context, req *v1.UpdateCheckItemReq) (res *v1.CheckItemRes, err error) { 25 | res, err = service.Checkitem().Update(ctx, req) 26 | if err != nil { 27 | glog.Errorf(ctx, "update checkitem err:%v", err) 28 | return 29 | } 30 | return 31 | } 32 | 33 | func (self *checkitem) Query(ctx context.Context, req *v1.QueryCheckItemReq) (res *v1.QueryCheckItemRes, err error) { 34 | res, err = service.Checkitem().Query(ctx, req) 35 | if err != nil { 36 | glog.Errorf(ctx, "query checkitem err:%v", err) 37 | return 38 | } 39 | return 40 | } 41 | 42 | func (self *checkitem) Delete(ctx context.Context, req *v1.DeleteCheckItemReq) (res v1.DeleteRes, err error) { 43 | err = service.Checkitem().Delete(ctx, req) 44 | if err != nil { 45 | glog.Errorf(ctx, "delete checkitem err:%v", err) 46 | res = v1.DeleteRes("删除失败") 47 | return 48 | } 49 | res = v1.DeleteRes("删除成功") 50 | return 51 | } 52 | -------------------------------------------------------------------------------- /internal/controller/check_tpl.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | v1 "go-ops/pkg/api/v1" 6 | ) 7 | 8 | var CheckTpl *checktpl = new(checktpl) 9 | 10 | type checktpl struct{} 11 | 12 | func (self *checktpl) Create(ctx context.Context, req *v1.AddCheckTplReq) (res *v1.CheckTplItemRes, err error) { 13 | return 14 | } 15 | 16 | func (self *checktpl) Update(ctx context.Context, req *v1.UpdateCheckTplReq) (res *v1.CheckTplItemRes, err error) { 17 | return 18 | } 19 | 20 | func (self *checktpl) Query(ctx context.Context, req *v1.QueryCheckTplReq) (res *v1.CheckTplItemRes, err error) { 21 | return 22 | } 23 | 24 | func (self *checktpl) Delete(ctx context.Context, req *v1.DeleteCheckTplReq) (res v1.DeleteRes, err error) { 25 | return 26 | } 27 | -------------------------------------------------------------------------------- /internal/controller/download_file.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/model" 6 | "go-ops/internal/peer" 7 | "go-ops/internal/service" 8 | v1 "go-ops/pkg/api/v1" 9 | ) 10 | 11 | var DownloadFileTask = &downloadFileTask{} 12 | 13 | type downloadFileTask struct { 14 | } 15 | 16 | func (self *downloadFileTask) Create(ctx context.Context, req *v1.DownloadFileReq) (res *v1.DownloadfileRes, err error) { 17 | 18 | createFunc := func(peerid string, job *model.DownloadFileJob) error { 19 | err = peer.SendMsgAsync(peer.GetOspPeer().PNet, job, peerid, "") 20 | return err 21 | } 22 | taskid, err := service.Task().CreateFileDownload(ctx, req, createFunc) 23 | if err != nil { 24 | return 25 | } 26 | res = new(v1.DownloadfileRes) 27 | res.Taskid = taskid 28 | return 29 | } 30 | 31 | func (self *downloadFileTask) Details(ctx context.Context, req *v1.DownloadFileDetailsReq) (res *v1.DownloadfileRes, err error) { 32 | return service.Task().GetFileDownloadTaskInfo(ctx, req.Taskid) 33 | } 34 | -------------------------------------------------------------------------------- /internal/controller/middleware.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "go-ops/internal/service" 5 | "go-ops/pkg/util" 6 | "net/http" 7 | 8 | "github.com/gogf/gf/v2/net/ghttp" 9 | "github.com/gogf/gf/v2/os/glog" 10 | ) 11 | 12 | const ( 13 | GoOpsHeaderAppId = "GO-OPS-X-APPID" 14 | GoOpsHeaderSignature = "GO-OPS-X-SIGNATURE" 15 | GoOpsHeaderTimestamp = "GO-OPS-X-TIMESTAMP" 16 | GoOpsHeaderNonce = "GO-OPS-X-NONCE" 17 | GoOpsHeaderToken = "GO-OPS-X-TOKEN" 18 | ) 19 | 20 | func MiddlewareGetApp(r *ghttp.Request) { 21 | appid := r.GetHeader(GoOpsHeaderAppId) 22 | if appid == "" { 23 | glog.Error(r.GetCtx(), "appid is empty") 24 | r.Response.WriteStatus(http.StatusForbidden) 25 | return 26 | } 27 | 28 | app, err := service.App().GetApp(r.GetCtx(), appid) 29 | if err != nil { 30 | glog.Errorf(r.GetCtx(), "get app:%s err:%v", appid, err) 31 | r.Response.WriteStatus(http.StatusForbidden) 32 | return 33 | } 34 | 35 | signature := r.GetHeader(GoOpsHeaderSignature) 36 | timestamp := r.GetHeader(GoOpsHeaderTimestamp) 37 | nonce := r.GetHeader(GoOpsHeaderNonce) 38 | body := r.GetBody() 39 | sign := util.GetSign(app.ApiKey, app.SecKey, nonce, timestamp, body) 40 | 41 | if sign != signature { 42 | glog.Errorf(r.GetCtx(), "sign is not match, req sign:%s server sign:%s", signature, sign) 43 | r.Response.WriteStatus(http.StatusForbidden) 44 | return 45 | } 46 | 47 | r.Middleware.Next() 48 | 49 | } 50 | 51 | func AuthUser(r *ghttp.Request) { 52 | 53 | appid := r.GetHeader(GoOpsHeaderAppId) 54 | if appid != "" { 55 | // 如果是app 56 | MiddlewareGetApp(r) 57 | } else { 58 | service.Auth().MiddlewareFunc()(r) 59 | r.Middleware.Next() 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /internal/controller/plugin.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | ) 8 | 9 | var Plugin *plugin = new(plugin) 10 | 11 | type plugin struct{} 12 | 13 | func (self *plugin) Create(ctx context.Context, req *v1.AddPluginReq) (res *v1.PluginItemRes, err error) { 14 | return service.Plugin().Create(ctx, req) 15 | } 16 | 17 | func (self *plugin) Update(ctx context.Context, req *v1.UpdatePluginReq) (res *v1.PluginItemRes, err error) { 18 | return service.Plugin().Update(ctx, req) 19 | } 20 | 21 | func (self *plugin) Query(ctx context.Context, req *v1.QueryPluginReq) (res *v1.QueryPluginRes, err error) { 22 | return service.Plugin().Query(ctx, req) 23 | } 24 | 25 | func (self *plugin) Delete(ctx context.Context, req *v1.DeletePluginReq) (res v1.DeleteRes, err error) { 26 | err = service.Plugin().Delete(ctx, req) 27 | if err != nil { 28 | res = v1.DeleteRes("删除失败") 29 | return 30 | } 31 | res = v1.DeleteRes("删除成功") 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /internal/controller/script.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | 8 | "github.com/gogf/gf/v2/os/glog" 9 | ) 10 | 11 | var Script *script = new(script) 12 | 13 | type script struct{} 14 | 15 | func (self *script) Create(ctx context.Context, req *v1.AddScriptReq) (res *v1.ScriptItemRes, err error) { 16 | 17 | res, err = service.Script().Create(ctx, req) 18 | if err != nil { 19 | glog.Errorf(ctx, "create script err:%v", err) 20 | } 21 | return 22 | } 23 | 24 | func (self *script) Update(ctx context.Context, req *v1.UpdateScriptReq) (res *v1.ScriptItemRes, err error) { 25 | res, err = service.Script().Update(ctx, req) 26 | if err != nil { 27 | glog.Errorf(ctx, "update script err:%v", err) 28 | } 29 | return 30 | } 31 | 32 | func (self *script) Query(ctx context.Context, req *v1.ScriptQueryReq) (res *v1.ScriptInfoRes, err error) { 33 | res, err = service.Script().Query(ctx, req) 34 | if err != nil { 35 | glog.Errorf(ctx, "query script err:%v", err) 36 | } 37 | return 38 | } 39 | 40 | func (self *script) Delete(ctx context.Context, req *v1.DeleteScriptReq) (res v1.DeleteScriptRes, err error) { 41 | err = service.Script().Delete(ctx, req) 42 | if err != nil { 43 | glog.Errorf(ctx, "delete script err:%v", err) 44 | res = v1.DeleteScriptRes("删除失败") 45 | return 46 | } 47 | res = v1.DeleteScriptRes("删除成功") 48 | return 49 | } 50 | -------------------------------------------------------------------------------- /internal/controller/task.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | ) 8 | 9 | var Task *task = new(task) 10 | 11 | type task struct{} 12 | 13 | func (self *task) Query(ctx context.Context, req *v1.TaskQueryReq) (res *v1.TaskInfoRes, err error) { 14 | return service.Task().QueryTask(ctx, req) 15 | } 16 | 17 | func (self *task) Get(ctx context.Context, req *v1.TaskInfoReq) (res v1.TaskDetailRes, err error) { 18 | taskinfo, err := service.Task().GetTaskInfo(ctx, req) 19 | if err != nil { 20 | return 21 | } 22 | res = v1.TaskDetailRes(*taskinfo) 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /internal/controller/task_cron.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | 8 | "github.com/gogf/gf/v2/os/glog" 9 | ) 10 | 11 | var TaskCron *taskcron = new(taskcron) 12 | 13 | type taskcron struct{} 14 | 15 | func (self *taskcron) Create(ctx context.Context, req *v1.AddCronTaskReq) (res *v1.CronTaskItemRes, err error) { 16 | res, err = service.TaskCron().Create(ctx, req) 17 | if err != nil { 18 | glog.Errorf(ctx, "create task cron err:%v", err) 19 | } 20 | return 21 | } 22 | 23 | func (self *taskcron) Update(ctx context.Context, req *v1.UpdateCronTaskReq) (res *v1.CronTaskItemRes, err error) { 24 | return service.TaskCron().Update(ctx, req) 25 | } 26 | 27 | func (self *taskcron) Delete(ctx context.Context, req *v1.DeleteCronTaskReq) (res *v1.DeleteTaskPresetRes, err error) { 28 | 29 | res = new(v1.DeleteTaskPresetRes) 30 | err = service.TaskCron().Delete(ctx, req) 31 | if err != nil { 32 | res.Message = err.Error() 33 | glog.Errorf(ctx, "delete task cron err:%v", err) 34 | return 35 | } 36 | res.Message = "DELETED SUCCESS!" 37 | return 38 | } 39 | 40 | func (self *taskcron) Query(ctx context.Context, req *v1.QueryCronTaskReq) (res *v1.QueryCronTaskRes, err error) { 41 | res, err = service.TaskCron().Query(ctx, req) 42 | if err != nil { 43 | glog.Errorf(ctx, "query task cron err:%v", err) 44 | } 45 | return 46 | } 47 | 48 | func (self *taskcron) Start(ctx context.Context, req *v1.StartCronTaskReq) (res v1.CronTaskOpRes, err error) { 49 | return 50 | } 51 | 52 | func (self *taskcron) Stop(ctx context.Context, req *v1.StopCronTaskReq) (res v1.CronTaskOpRes, err error) { 53 | return 54 | } 55 | -------------------------------------------------------------------------------- /internal/controller/task_preset.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | ) 8 | 9 | var TaskPreset *taskPreset = new(taskPreset) 10 | 11 | type taskPreset struct{} 12 | 13 | func (self *taskPreset) Create(ctx context.Context, req *v1.AddTaskPresetReq) (res *v1.TaskPresetItemRes, err error) { 14 | return service.TaskPreset().Create(ctx, req) 15 | } 16 | 17 | func (self *taskPreset) Update(ctx context.Context, req *v1.UpdateTaskPresetReq) (res *v1.TaskPresetItemRes, err error) { 18 | return service.TaskPreset().Update(ctx, req) 19 | } 20 | 21 | func (self *taskPreset) Delete(ctx context.Context, req *v1.DeleteTaskPresetReq) (res *v1.DeleteTaskPresetRes, err error) { 22 | err = service.TaskPreset().Delete(ctx, req) 23 | res = new(v1.DeleteTaskPresetRes) 24 | if err != nil { 25 | res.Message = err.Error() 26 | return 27 | } 28 | res.Message = "DELETED SUCCESS!" 29 | return 30 | } 31 | 32 | func (self *taskPreset) Query(ctx context.Context, req *v1.QueryTaskPresetReq) (res *v1.QueryTaskPresetRes, err error) { 33 | return service.TaskPreset().Query(ctx, req) 34 | } 35 | -------------------------------------------------------------------------------- /internal/controller/user.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/service" 6 | v1 "go-ops/pkg/api/v1" 7 | 8 | "github.com/gogf/gf/v2/util/gconv" 9 | ) 10 | 11 | type user struct{} 12 | 13 | var User = user{} 14 | 15 | func (self *user) CurrentInfo(ctx context.Context, req *v1.CurrentUserInfoReq) (res *v1.UserInfoRes, erro error) { 16 | 17 | id := service.Auth().GetIdentity(ctx) 18 | 19 | uid := gconv.String(id) 20 | 21 | user, err := service.User().Get(ctx, uid) 22 | if err != nil { 23 | return 24 | } 25 | 26 | res = &v1.UserInfoRes{ 27 | Uid: uid, 28 | Username: user.Username, 29 | Email: user.Email, 30 | Avatar: user.Avatar, 31 | Phone: user.Phone, 32 | } 33 | return 34 | 35 | } 36 | -------------------------------------------------------------------------------- /internal/controller/vm.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/model" 6 | "go-ops/internal/peer" 7 | "go-ops/internal/service" 8 | v1 "go-ops/pkg/api/v1" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | var VM *vm = new(vm) 14 | 15 | type vm struct{} 16 | 17 | func (self *vm) Create(ctx context.Context, req *v1.AddVmReq) (res *v1.VmItemRes, err error) { 18 | return service.VM().Create(ctx, req) 19 | } 20 | 21 | func (self *vm) Update(ctx context.Context, req *v1.UpdateVmReq) (res *v1.VmItemRes, err error) { 22 | return service.VM().Update(ctx, req) 23 | } 24 | 25 | func (self *vm) Query(ctx context.Context, req *v1.QueryVmReq) (res *v1.QueryVmRes, err error) { 26 | res, err = service.VM().Query(ctx, req) 27 | if err != nil { 28 | return 29 | } 30 | if len(res.List) > 0 { 31 | return 32 | } 33 | 34 | req.Hostname = strings.TrimSpace(req.Hostname) 35 | 36 | if req.Hostname == "" { 37 | return 38 | } 39 | 40 | // 没有查找到主机信息,需要到网络中查找 41 | 42 | err = peer.SendMsgBroadCast(peer.GetOspPeer().PNet, &model.GetPeerInfo{HostName: req.Hostname}) 43 | if err != nil { 44 | return 45 | } 46 | 47 | for i := 0; i < 30; i++ { 48 | res, err = service.VM().Query(ctx, req) 49 | if err != nil { 50 | return 51 | } 52 | if len(res.List) > 0 { 53 | return 54 | } 55 | time.Sleep(time.Second * 2) 56 | } 57 | return 58 | } 59 | 60 | func (self *vm) Delete(ctx context.Context, req *v1.DeleteVmReq) (res v1.DeleteRes, err error) { 61 | err = service.VM().Delete(ctx, req) 62 | if err != nil { 63 | res = v1.DeleteRes("删除失败") 64 | return 65 | } 66 | res = v1.DeleteRes("删除成功") 67 | return 68 | } 69 | -------------------------------------------------------------------------------- /internal/model/agent_info.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type AgentInfo struct { 4 | Name string `json:"name" dc:"agent 名称"` 5 | Version string `json:"version" dc:"版本信息"` 6 | UrlAddress string `json:"urlAddress" dc:"下载地址"` 7 | Status string `json:"status" dc:"agent状态"` 8 | Timeout int `json:"timeout" dc:"执行命令超时时间"` 9 | } 10 | 11 | type AgentDetails struct { 12 | AgentInfo 13 | Details string `json:"details" dc:"agent 运行详细信息"` 14 | } 15 | -------------------------------------------------------------------------------- /internal/model/download_file.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "go-ops/pkg/message" 5 | "go-ops/pkg/util" 6 | "reflect" 7 | ) 8 | 9 | type DownloadFileInfo struct { 10 | Filename string `json:"filename" dc:"文件名称"` // 文件名称 11 | Address string `json:"address" dc:"文件的下载url地址"` // 文件下载地址 12 | Path string `json:"path" dc:"文件的保存路径"` // 文件保存路径 13 | AutoCreatePath bool `json:"auto_create_path" dc:"是否自动创建文件夹"` // 自动创建文件夹 14 | Replace bool `json:"replace" dc:"如果文件已经存在,是否替换文件"` // 是否替换 15 | } 16 | 17 | type DownloadFileRes struct { 18 | Filename string `json:"filename" dc:"文件名"` // 19 | Code ResCode `json:"code" dc:"代码"` 20 | Msg string `json:"msg"` 21 | } 22 | 23 | type DownloadFileJobRes struct { 24 | PeerId string `json:"peerid" dc:"节点id"` 25 | Jobid string `json:"jobid" dc:"任务id"` // 任务id 26 | *DownloadFileRes 27 | } 28 | 29 | type DownloadFileJob struct { 30 | Jobid string `json:"jobid"` // 任务id 31 | *DownloadFileInfo 32 | } 33 | 34 | func init() { 35 | message.RegisterMessage(&message.MessageMeta{ 36 | Type: reflect.TypeOf((*DownloadFileJob)(nil)).Elem(), 37 | ID: uint32(util.StringHash("model.DownloadFileJob")), 38 | }) 39 | message.RegisterMessage(&message.MessageMeta{ 40 | Type: reflect.TypeOf((*DownloadFileJobRes)(nil)).Elem(), 41 | ID: uint32(util.StringHash("model.DownloadFileJobRes")), 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /internal/model/entity/agent_info.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // AgentInfo is the golang structure for table agent_info. 12 | type AgentInfo struct { 13 | Id int `json:"id" ` // 14 | Peerid string `json:"peerid" ` // 节点id 15 | Name string `json:"name" ` // agent名称 16 | ExpectedStatus string `json:"expectedStatus" ` // 期望状态 17 | Status string `json:"status" ` // 18 | IsDefault int `json:"isDefault" ` // 19 | Timeout int `json:"timeout" ` // 启动超时时间 20 | Created *gtime.Time `json:"created" ` // 21 | Updated *gtime.Time `json:"updated" ` // 22 | Version string `json:"version" ` // 版本信息 23 | } 24 | -------------------------------------------------------------------------------- /internal/model/entity/app.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // App is the golang structure for table app. 12 | type App struct { 13 | Id int `json:"id" ` // 14 | Appid string `json:"appid" ` // 15 | ApiKey string `json:"apiKey" ` // 16 | SecKey string `json:"secKey" ` // 17 | Owner string `json:"owner" ` // 18 | Name string `json:"name" ` // 应用名 19 | Status int `json:"status" ` // 1启用 0 禁用 20 | OwnerUid string `json:"ownerUid" ` // 拥有者uid 21 | CreatedAt *gtime.Time `json:"createdAt" ` // 22 | UpdatedAt *gtime.Time `json:"updatedAt" ` // 23 | } 24 | -------------------------------------------------------------------------------- /internal/model/entity/check_item.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // CheckItem is the golang structure for table check_item. 12 | type CheckItem struct { 13 | Id int `json:"id" ` // 14 | CheckItemId string `json:"checkItemId" ` // 15 | Name string `json:"name" ` // 检查项名称 16 | Desc string `json:"desc" ` // 检查项描述 17 | Type string `json:"type" ` // 18 | Content string `json:"content" ` // 检查项内容 19 | Creater string `json:"creater" ` // 创建人 20 | Updater string `json:"updater" ` // 更新人 21 | Created *gtime.Time `json:"created" ` // 22 | Updated *gtime.Time `json:"updated" ` // 23 | Weight float64 `json:"weight" ` // 权重 24 | WaitTime int `json:"waitTime" ` // 超时时间 25 | Cmd string `json:"cmd" ` // 脚本执行解释器 26 | } 27 | -------------------------------------------------------------------------------- /internal/model/entity/check_tpl.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // CheckTpl is the golang structure for table check_tpl. 12 | type CheckTpl struct { 13 | Id int `json:"id" ` // 14 | Tid string `json:"tid" ` // 唯一id 15 | Name string `json:"name" ` // 名称 16 | Description string `json:"description" ` // 描述 17 | Type string `json:"type" ` // 类型 18 | Creater string `json:"creater" ` // 创建人 19 | Updater string `json:"updater" ` // 更新人 20 | Created *gtime.Time `json:"created" ` // 21 | Updated *gtime.Time `json:"updated" ` // 22 | } 23 | -------------------------------------------------------------------------------- /internal/model/entity/check_tpl_detail.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | // CheckTplDetail is the golang structure for table check_tpl_detail. 8 | type CheckTplDetail struct { 9 | Id int `json:"id" ` // 10 | Tid string `json:"tid" ` // 模板id 11 | Cid string `json:"cid" ` // 检查项id 12 | Sort int `json:"sort" ` // 排序 13 | Weight float64 `json:"weight" ` // 权重 14 | } 15 | -------------------------------------------------------------------------------- /internal/model/entity/cron_task.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // CronTask is the golang structure for table cron_task. 12 | type CronTask struct { 13 | Id int `json:"id" ` // 14 | CronUid string `json:"cronUid" ` // 15 | Name string `json:"name" ` // 定时任务名称 16 | Content string `json:"content" ` // 定时任务内容 17 | CronExpr string `json:"cronExpr" ` // 定时任务表达式 18 | LastrunTime *gtime.Time `json:"lastrunTime" ` // 最后执行时间 19 | NextrunTime *gtime.Time `json:"nextrunTime" ` // 20 | Status string `json:"status" ` // 状态 running stopped 21 | Creater string `json:"creater" ` // 创建人 22 | Updater string `json:"updater" ` // 更新人 23 | Created *gtime.Time `json:"created" ` // 24 | Updated *gtime.Time `json:"updated" ` // 25 | Type string `json:"type" ` // 任务类型 26 | } 27 | -------------------------------------------------------------------------------- /internal/model/entity/plugin.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // Plugin is the golang structure for table plugin. 12 | type Plugin struct { 13 | Id int `json:"id" ` // 14 | Uuid string `json:"uuid" ` // 插件uuid 15 | Name string `json:"name" ` // 插件名 16 | PackageName string `json:"packageName" ` // 包名 17 | Os string `json:"os" ` // 操作系统 18 | Arch string `json:"arch" ` // 架构 19 | Md5 string `json:"md5" ` // 包md5名称 20 | Creater string `json:"creater" ` // 创建人 21 | Updater string `json:"updater" ` // 更新人 22 | Created *gtime.Time `json:"created" ` // 23 | Updated *gtime.Time `json:"updated" ` // 24 | } 25 | -------------------------------------------------------------------------------- /internal/model/entity/script.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // Script is the golang structure for table script. 12 | type Script struct { 13 | Id int `json:"id" ` // 14 | Name string `json:"name" ` // 命令名称 15 | Content string `json:"content" ` // 脚本内容 16 | Args string `json:"args" ` // 参数信息 17 | Desc string `json:"desc" ` // 描述信息 18 | Type string `json:"type" ` // 脚本类型shell或者powershell 19 | OwnerType string `json:"ownerType" ` // 命令拥有者类型 20 | OwnerUid string `json:"ownerUid" ` // 拥有者uid 21 | Created *gtime.Time `json:"created" ` // 22 | Updated *gtime.Time `json:"updated" ` // 23 | ScriptUid string `json:"scriptUid" ` // 24 | WaitTime int `json:"waitTime" ` // 脚本超时时间 25 | Cmd string `json:"cmd" ` // 脚本解释器 26 | Ext string `json:"ext" ` // 脚本文件扩展名 27 | } 28 | -------------------------------------------------------------------------------- /internal/model/entity/task.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // Task is the golang structure for table task. 12 | type Task struct { 13 | Id int `json:"id" ` // 14 | TaskId string `json:"taskId" ` // 任务id 15 | Type string `json:"type" ` // 任务类型 16 | Content string `json:"content" ` // 任务内容 17 | Name string `json:"name" ` // 任务名称 18 | Reqid string `json:"reqid" ` // 请求id 19 | ParentId string `json:"parentId" ` // 20 | Status string `json:"status" ` // 21 | Created *gtime.Time `json:"created" ` // 22 | Updated *gtime.Time `json:"updated" ` // 23 | Creater string `json:"creater" ` // 创建人 24 | } 25 | -------------------------------------------------------------------------------- /internal/model/entity/task_preset.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // TaskPreset is the golang structure for table task_preset. 12 | type TaskPreset struct { 13 | Id int `json:"id" ` // 14 | Uuid string `json:"uuid" ` // 15 | Name string `json:"name" ` // 任务名 16 | Type string `json:"type" ` // 任务类型 17 | Content string `json:"content" ` // 任务内容 18 | Peers string `json:"peers" ` // 主机列表 19 | Creater string `json:"creater" ` // 创建人 20 | Created *gtime.Time `json:"created" ` // 创建时间 21 | Updated *gtime.Time `json:"updated" ` // 更新时间 22 | Updater string `json:"updater" ` // 更新人 23 | } 24 | -------------------------------------------------------------------------------- /internal/model/entity/user.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // User is the golang structure for table user. 12 | type User struct { 13 | Id int `json:"id" ` // 14 | Uid string `json:"uid" ` // 15 | Username string `json:"username" ` // 16 | Passwd string `json:"passwd" ` // 17 | Email string `json:"email" ` // 18 | Created *gtime.Time `json:"created" ` // 19 | Updated *gtime.Time `json:"updated" ` // 20 | Phone string `json:"phone" ` // 21 | Avatar string `json:"avatar" ` // 头像 22 | Status string `json:"status" ` // 状态 1 启用 2 禁用 23 | } 24 | -------------------------------------------------------------------------------- /internal/model/entity/vm.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package entity 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/os/gtime" 9 | ) 10 | 11 | // Vm is the golang structure for table vm. 12 | type Vm struct { 13 | Id int `json:"id" ` // 14 | Uuid string `json:"uuid" ` // 主机uuid 15 | Name string `json:"name" ` // 16 | Hostname string `json:"hostname" ` // 17 | OsType string `json:"osType" ` // 操作系统类型 18 | OsInfo string `json:"osInfo" ` // 操作系统信息 19 | Hosttype string `json:"hosttype" ` // 主机类型 20 | Networktype string `json:"networktype" ` // 网络类型 21 | PrivateIp string `json:"privateIp" ` // 22 | PublicIp string `json:"publicIp" ` // 23 | Created *gtime.Time `json:"created" ` // 24 | Updated *gtime.Time `json:"updated" ` // 25 | Creater string `json:"creater" ` // 创建人 26 | Address string `json:"address" ` // 27 | PeerId string `json:"peerId" ` // 28 | } 29 | -------------------------------------------------------------------------------- /internal/model/fileinfo.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "go-ops/pkg/message" 5 | "go-ops/pkg/util" 6 | "reflect" 7 | "time" 8 | ) 9 | 10 | type FileInfo struct { 11 | Name string `json:"name" dc:"文件名称"` 12 | Type string `json:"type" dc:"文件类型, dir 表示文件夹"` 13 | Size int64 `json:"size" dc:"大小"` 14 | Path string `json:"path" dc:"路径"` 15 | ModTime time.Time `json:"mtime" dc:"修改时间"` 16 | } 17 | 18 | type PeerListFileInfo struct { 19 | Peerid string `json:"peerid" dc:"节点id"` 20 | Path string `json:"path" dc:"文件夹路径"` 21 | } 22 | 23 | type PeerListFileInfoRes struct { 24 | Peerid string `json:"peerid" dc:"节点id"` 25 | Path string `json:"path" dc:"文件夹路径"` 26 | List []*FileInfo `json:"list" dc:"文件列表"` 27 | Error string `json:"error" dc:"报错信息"` 28 | } 29 | 30 | type PeerNewDir struct { 31 | Peerid string `json:"peerid" dc:"节点id"` 32 | Path string `json:"path" dc:"文件夹路径, 如果不存在会递归创建"` 33 | } 34 | 35 | type PeerMoveFile struct { 36 | Peerid string `json:"peerid" dc:"节点id"` 37 | Src string `json:"src" dc:"源文件"` 38 | Dst string `json:"dst" dc:"目标文件"` 39 | } 40 | 41 | type PeerDeleteFile struct { 42 | Peerid string `json:"peerid" dc:"节点id"` 43 | Path string `json:"path" dc:"文件路径"` 44 | } 45 | 46 | func init() { 47 | message.RegisterMessage(&message.MessageMeta{ 48 | Type: reflect.TypeOf((*PeerListFileInfo)(nil)).Elem(), 49 | ID: uint32(util.StringHash("model.PeerListFileInfo")), 50 | }) 51 | 52 | message.RegisterMessage(&message.MessageMeta{ 53 | Type: reflect.TypeOf((*PeerListFileInfoRes)(nil)).Elem(), 54 | ID: uint32(util.StringHash("model.PeerListFileInfoRes")), 55 | }) 56 | 57 | message.RegisterMessage(&message.MessageMeta{ 58 | Type: reflect.TypeOf((*PeerNewDir)(nil)).Elem(), 59 | ID: uint32(util.StringHash("model.PeerNewDir")), 60 | }) 61 | 62 | message.RegisterMessage(&message.MessageMeta{ 63 | Type: reflect.TypeOf((*PeerMoveFile)(nil)).Elem(), 64 | ID: uint32(util.StringHash("model.PeerMoveFile")), 65 | }) 66 | 67 | message.RegisterMessage(&message.MessageMeta{ 68 | Type: reflect.TypeOf((*PeerDeleteFile)(nil)).Elem(), 69 | ID: uint32(util.StringHash("model.PeerDeleteFile")), 70 | }) 71 | 72 | } 73 | -------------------------------------------------------------------------------- /internal/model/peer.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "go-ops/pkg/message" 5 | "go-ops/pkg/util" 6 | "reflect" 7 | ) 8 | 9 | type PeerInfo struct { 10 | PeerId string `json:"peerId" ` // 节点uuid 11 | HostName string `json:"hostname"` // 节点hostname 12 | Name string `json:"name"` // 节点名称 13 | Address string `json:"address"` // 节点地址 14 | PublicIp string `json:"publicIp"` // 节点ip 15 | Os string `json:"os"` 16 | Arch string `json:"arch"` 17 | } 18 | 19 | type GetPeerInfo struct { 20 | HostName string `json:"hostname"` // 节点hostname 21 | } 22 | 23 | func init() { 24 | message.RegisterMessage(&message.MessageMeta{ 25 | Type: reflect.TypeOf((*PeerInfo)(nil)).Elem(), 26 | ID: uint32(util.StringHash("model.PeerInfo")), 27 | }) 28 | 29 | message.RegisterMessage(&message.MessageMeta{ 30 | Type: reflect.TypeOf((*GetPeerInfo)(nil)).Elem(), 31 | ID: uint32(util.StringHash("model.GetPeerInfo")), 32 | }) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /internal/packed/packed.go: -------------------------------------------------------------------------------- 1 | package packed 2 | -------------------------------------------------------------------------------- /internal/peer/handlermsg.go: -------------------------------------------------------------------------------- 1 | package peer 2 | -------------------------------------------------------------------------------- /internal/peer/osp_peer.go: -------------------------------------------------------------------------------- 1 | package peer 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "go-ops/internal/model" 8 | "go-ops/internal/service" 9 | 10 | "github.com/luxingwen/pnet" 11 | "github.com/luxingwen/pnet/config" 12 | "github.com/luxingwen/pnet/log" 13 | ) 14 | 15 | type OspPeer struct { 16 | *pnet.PNet 17 | } 18 | 19 | func (self *OspPeer) HandlerFunc(msg interface{}, msgID []byte, srcID, rpath string, pn *pnet.PNet) { 20 | switch v := msg.(type) { 21 | case *model.ResponseResCmd: 22 | fmt.Println("res cmd:", v.Jobid) 23 | err := service.Task().UpdateSubScriptTask(context.Background(), v) 24 | if err != nil { 25 | fmt.Println("update err:", err) 26 | } 27 | case *model.DownloadFileJobRes: 28 | err := service.Task().UpdateDownloadFileTask(context.Background(), v) 29 | if err != nil { 30 | fmt.Println("update err:", err) 31 | } 32 | case *model.PeerInfo: 33 | err := service.VM().Check(context.Background(), v) 34 | if err != nil { 35 | fmt.Println("check vm err:", err) 36 | } 37 | default: 38 | b, _ := json.Marshal(v) 39 | log.Error("msg handler not found,msg: %s", string(b)) 40 | } 41 | } 42 | 43 | var ospPeer *OspPeer 44 | 45 | func InitOspPeer(id string, conf *config.Config) (err error) { 46 | 47 | ospPeer = &OspPeer{} 48 | 49 | pn, err := NewPnet(id, conf, ospPeer.HandlerFunc) 50 | if err != nil { 51 | return 52 | } 53 | ospPeer.PNet = pn 54 | err = pn.Start() 55 | if err != nil { 56 | return 57 | } 58 | return 59 | } 60 | 61 | func GetOspPeer() *OspPeer { 62 | if ospPeer == nil { 63 | panic("osp peer is nil") 64 | } 65 | return ospPeer 66 | } 67 | -------------------------------------------------------------------------------- /internal/peer/peer.go: -------------------------------------------------------------------------------- 1 | package peer 2 | 3 | import ( 4 | "go-ops/pkg/message" 5 | "time" 6 | 7 | "github.com/luxingwen/pnet/log" 8 | "github.com/luxingwen/pnet/protos" 9 | 10 | "github.com/luxingwen/pnet/config" 11 | 12 | "github.com/luxingwen/pnet" 13 | "github.com/luxingwen/pnet/node" 14 | ) 15 | 16 | var defaultPN *pnet.PNet 17 | 18 | type HandlerPNetMsg func(msg interface{}, msgID []byte, srcID, rpath string, pn *pnet.PNet) 19 | 20 | func NewPnet(id string, conf *config.Config, h HandlerPNetMsg) (pn *pnet.PNet, err error) { 21 | pn, err = pnet.NewPNet(id, conf) 22 | if err != nil { 23 | return 24 | } 25 | 26 | pn.ApplyMiddleware(node.BytesReceived{func(msg, msgID []byte, srcID, rpath string, remoteNode *node.RemoteNode) ([]byte, bool) { 27 | v, err := message.JSONCodec.Decode(msg) 28 | if err != nil { 29 | log.Error("json decode err:", err) 30 | return nil, true 31 | } 32 | 33 | h(v, msgID, srcID, rpath, pn) 34 | return nil, true 35 | }, 0}) 36 | 37 | pn.ApplyMiddleware(node.LocalNodeStarted{func(lc *node.LocalNode) bool { 38 | lc.SetReady(true) 39 | return true 40 | }, 0}) 41 | 42 | return 43 | } 44 | 45 | // 发送异步消息 46 | func SendMsgAsync(pn *pnet.PNet, msg interface{}, srcID, rpath string) (err error) { 47 | data, err := message.JSONCodec.Encode(msg) 48 | if err != nil { 49 | log.Error("json encode err:", err) 50 | return 51 | } 52 | _, err = pn.SendBytesRelayAsync(data, srcID) 53 | return 54 | } 55 | 56 | // 发送同步消息 57 | func SendMsgSync(pn *pnet.PNet, msg interface{}, srcID, rpath string) (r []byte, err error) { 58 | return SendMsgSyncWithTimeout(pn, msg, srcID, rpath, 0) 59 | } 60 | 61 | // 发送同步消息 62 | func SendMsgSyncWithTimeout(pn *pnet.PNet, msg interface{}, srcID, rpath string, timeout time.Duration) (r []byte, err error) { 63 | data, err := message.JSONCodec.Encode(msg) 64 | if err != nil { 65 | log.Error("json encode err:", err) 66 | return 67 | } 68 | r, _, err = pn.SendBytesRelaySyncWithTimeout(data, srcID, timeout) 69 | return 70 | } 71 | 72 | // 回复消息 73 | func SendMsgReplay(pn *pnet.PNet, msg interface{}, msgID []byte, srcID, rpath string) (err error) { 74 | data, err := message.JSONCodec.Encode(msg) 75 | if err != nil { 76 | log.Error("json encode err:", err) 77 | return 78 | } 79 | _, err = pn.SendBytesRelayReply(msgID, data, srcID) 80 | return 81 | } 82 | 83 | func SendMsgBroadCast(pn *pnet.PNet, msg interface{}) (err error) { 84 | data, err := message.JSONCodec.Encode(msg) 85 | if err != nil { 86 | log.Error("json encode err:", err) 87 | return 88 | } 89 | 90 | _, err = pn.SendMessageAsync(pn.GetLocalNode().NewBraodcastMessage(data), protos.BROADCAST) 91 | return 92 | } 93 | -------------------------------------------------------------------------------- /internal/service/auth.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | v1 "go-ops/pkg/api/v1" 6 | "time" 7 | 8 | "github.com/gogf/gf/v2/frame/g" 9 | 10 | jwt "github.com/gogf/gf-jwt/v2" 11 | ) 12 | 13 | var authService *jwt.GfJWTMiddleware 14 | 15 | func Auth() *jwt.GfJWTMiddleware { 16 | return authService 17 | } 18 | 19 | var jwtKey string = "Go-ops-apiserver-jwt-key" 20 | 21 | func init() { 22 | auth := jwt.New(&jwt.GfJWTMiddleware{ 23 | Realm: "Go-ops apiserver", 24 | Key: []byte(jwtKey), 25 | Timeout: time.Minute * 10, 26 | MaxRefresh: time.Minute * 20, 27 | IdentityKey: "uid", 28 | TokenLookup: "header: GO-OPS-X-TOKEN, query: token, cookie: jwt", 29 | TokenHeadName: "Bearer", 30 | TimeFunc: time.Now, 31 | Authenticator: Authenticator, 32 | Unauthorized: Unauthorized, 33 | PayloadFunc: PayloadFunc, 34 | IdentityHandler: IdentityHandler, 35 | }) 36 | authService = auth 37 | } 38 | 39 | // PayloadFunc is a callback function that will be called during login. 40 | // Using this function it is possible to add additional payload data to the webtoken. 41 | // The data is then made available during requests via c.Get("JWT_PAYLOAD"). 42 | // Note that the payload is not encrypted. 43 | // The attributes mentioned on jwt.io can't be used as keys for the map. 44 | // Optional, by default no additional data will be set. 45 | func PayloadFunc(data interface{}) jwt.MapClaims { 46 | claims := jwt.MapClaims{} 47 | params := data.(map[string]interface{}) 48 | if len(params) > 0 { 49 | for k, v := range params { 50 | claims[k] = v 51 | } 52 | } 53 | return claims 54 | } 55 | 56 | // IdentityHandler get the identity from JWT and set the identity for every request 57 | // Using this function, by r.GetParam("id") get identity 58 | func IdentityHandler(ctx context.Context) interface{} { 59 | claims := jwt.ExtractClaims(ctx) 60 | return claims[authService.IdentityKey] 61 | } 62 | 63 | // Unauthorized is used to define customized Unauthorized callback function. 64 | func Unauthorized(ctx context.Context, code int, message string) { 65 | 66 | r := g.RequestFromCtx(ctx) 67 | 68 | r.Response.WriteStatus(code, g.Map{ 69 | "code": code, 70 | "message": message, 71 | }) 72 | r.ExitAll() 73 | } 74 | 75 | // Authenticator is used to validate login parameters. 76 | // It must return user data as user identifier, it will be stored in Claim Array. 77 | // if your identityKey is 'id', your user data must have 'id' 78 | // Check error (e) to determine the appropriate error message. 79 | func Authenticator(ctx context.Context) (interface{}, error) { 80 | var ( 81 | r = g.RequestFromCtx(ctx) 82 | in v1.AuthLoginReq 83 | ) 84 | if err := r.Parse(&in); err != nil { 85 | return "", err 86 | } 87 | 88 | user, err := User().SignIn(ctx, &in) 89 | 90 | if err != nil { 91 | return nil, err 92 | } 93 | 94 | if user != nil { 95 | return g.Map{ 96 | "uid": user.Uid, 97 | "username": user.Username, 98 | }, nil 99 | } 100 | 101 | return nil, jwt.ErrFailedAuthentication 102 | } 103 | -------------------------------------------------------------------------------- /internal/service/checktpl.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "go-ops/internal/model/entity" 7 | "go-ops/internal/service/internal/dao" 8 | v1 "go-ops/pkg/api/v1" 9 | 10 | "github.com/gogf/gf/v2/database/gdb" 11 | "github.com/gogf/gf/v2/util/guid" 12 | ) 13 | 14 | type sCheckTpl struct { 15 | } 16 | 17 | var ( 18 | insCheckTpl = sCheckTpl{} 19 | ) 20 | 21 | func CheckTpl() *sCheckTpl { 22 | return &insCheckTpl 23 | } 24 | 25 | func (selef *sCheckTpl) Create(ctx context.Context, req *v1.AddCheckTplReq) (err error) { 26 | 27 | checktpl := &entity.CheckTpl{ 28 | Tid: guid.S(), 29 | Name: req.Name, 30 | Description: req.Desc, 31 | Type: req.Type, 32 | } 33 | 34 | checktplDetails := make([]*entity.CheckTplDetail, 0) 35 | 36 | for _, item := range req.Items { 37 | 38 | checktplDetails = append(checktplDetails, &entity.CheckTplDetail{ 39 | Tid: checktpl.Tid, 40 | Cid: item.ItemId, 41 | Weight: item.Weight, 42 | }) 43 | 44 | } 45 | 46 | err = dao.CheckTpl.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { 47 | _, err = dao.CheckTpl.Ctx(ctx).Data(checktpl).Insert() 48 | 49 | if err != nil { 50 | return err 51 | } 52 | 53 | _, err = dao.CheckTplDetail.Ctx(ctx).Data(checktplDetails).Insert() 54 | return err 55 | }) 56 | return 57 | } 58 | 59 | func (self *sCheckTpl) Update(ctx context.Context, req *v1.UpdateCheckTplReq) (err error) { 60 | var checkTpl *entity.CheckTpl 61 | 62 | err = dao.CheckTpl.Ctx(ctx).Where("tid = ?", req.Tid).Scan(&checkTpl) 63 | if err != nil { 64 | return 65 | } 66 | 67 | if checkTpl == nil { 68 | err = errors.New("not found:" + req.Tid) 69 | return 70 | } 71 | 72 | checktplDetails := make([]*entity.CheckTplDetail, 0) 73 | 74 | for _, item := range req.Items { 75 | 76 | checktplDetails = append(checktplDetails, &entity.CheckTplDetail{ 77 | Tid: checkTpl.Tid, 78 | Cid: item.ItemId, 79 | Weight: item.Weight, 80 | }) 81 | 82 | } 83 | 84 | dao.CheckTplDetail.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { 85 | _, err = dao.CheckTplDetail.Ctx(ctx).Where("tid = ?", req.Tid).Delete() 86 | if err != nil { 87 | return err 88 | } 89 | 90 | _, err = dao.CheckTplDetail.Ctx(ctx).Data(checktplDetails).Insert() 91 | if err != nil { 92 | return err 93 | } 94 | // _, err = dao.CheckTpl.Ctx(ctx).Data(checktplDetails).Insert() 95 | // if err != nil { 96 | // return err 97 | // } 98 | 99 | return err 100 | }) 101 | 102 | return 103 | } 104 | -------------------------------------------------------------------------------- /internal/service/internal/dao/agent_info.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalAgentInfoDao is internal type for wrapping internal DAO implements. 12 | type internalAgentInfoDao = *internal.AgentInfoDao 13 | 14 | // agentInfoDao is the data access object for table agent_info. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type agentInfoDao struct { 17 | internalAgentInfoDao 18 | } 19 | 20 | var ( 21 | // AgentInfo is globally public accessible object for table agent_info operations. 22 | AgentInfo = agentInfoDao{ 23 | internal.NewAgentInfoDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/app.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalAppDao is internal type for wrapping internal DAO implements. 12 | type internalAppDao = *internal.AppDao 13 | 14 | // appDao is the data access object for table app. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type appDao struct { 17 | internalAppDao 18 | } 19 | 20 | var ( 21 | // App is globally public accessible object for table app operations. 22 | App = appDao{ 23 | internal.NewAppDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/check_item.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalCheckItemDao is internal type for wrapping internal DAO implements. 12 | type internalCheckItemDao = *internal.CheckItemDao 13 | 14 | // checkItemDao is the data access object for table check_item. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type checkItemDao struct { 17 | internalCheckItemDao 18 | } 19 | 20 | var ( 21 | // CheckItem is globally public accessible object for table check_item operations. 22 | CheckItem = checkItemDao{ 23 | internal.NewCheckItemDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/check_tpl.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalCheckTplDao is internal type for wrapping internal DAO implements. 12 | type internalCheckTplDao = *internal.CheckTplDao 13 | 14 | // checkTplDao is the data access object for table check_tpl. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type checkTplDao struct { 17 | internalCheckTplDao 18 | } 19 | 20 | var ( 21 | // CheckTpl is globally public accessible object for table check_tpl operations. 22 | CheckTpl = checkTplDao{ 23 | internal.NewCheckTplDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/check_tpl_detail.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalCheckTplDetailDao is internal type for wrapping internal DAO implements. 12 | type internalCheckTplDetailDao = *internal.CheckTplDetailDao 13 | 14 | // checkTplDetailDao is the data access object for table check_tpl_detail. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type checkTplDetailDao struct { 17 | internalCheckTplDetailDao 18 | } 19 | 20 | var ( 21 | // CheckTplDetail is globally public accessible object for table check_tpl_detail operations. 22 | CheckTplDetail = checkTplDetailDao{ 23 | internal.NewCheckTplDetailDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/cron_task.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalCronTaskDao is internal type for wrapping internal DAO implements. 12 | type internalCronTaskDao = *internal.CronTaskDao 13 | 14 | // cronTaskDao is the data access object for table cron_task. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type cronTaskDao struct { 17 | internalCronTaskDao 18 | } 19 | 20 | var ( 21 | // CronTask is globally public accessible object for table cron_task operations. 22 | CronTask = cronTaskDao{ 23 | internal.NewCronTaskDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/internal/app.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "context" 9 | "github.com/gogf/gf/v2/database/gdb" 10 | "github.com/gogf/gf/v2/frame/g" 11 | ) 12 | 13 | // AppDao is the data access object for table app. 14 | type AppDao struct { 15 | table string // table is the underlying table name of the DAO. 16 | group string // group is the database configuration group name of current DAO. 17 | columns AppColumns // columns contains all the column names of Table for convenient usage. 18 | } 19 | 20 | // AppColumns defines and stores column names for table app. 21 | type AppColumns struct { 22 | Id string // 23 | Appid string // 24 | ApiKey string // 25 | SecKey string // 26 | Owner string // 27 | Name string // 应用名 28 | Status string // 1启用 0 禁用 29 | OwnerUid string // 拥有者uid 30 | CreatedAt string // 31 | UpdatedAt string // 32 | } 33 | 34 | // appColumns holds the columns for table app. 35 | var appColumns = AppColumns{ 36 | Id: "id", 37 | Appid: "appid", 38 | ApiKey: "api_key", 39 | SecKey: "sec_key", 40 | Owner: "owner", 41 | Name: "name", 42 | Status: "status", 43 | OwnerUid: "owner_uid", 44 | CreatedAt: "created_at", 45 | UpdatedAt: "updated_at", 46 | } 47 | 48 | // NewAppDao creates and returns a new DAO object for table data access. 49 | func NewAppDao() *AppDao { 50 | return &AppDao{ 51 | group: "default", 52 | table: "app", 53 | columns: appColumns, 54 | } 55 | } 56 | 57 | // DB retrieves and returns the underlying raw database management object of current DAO. 58 | func (dao *AppDao) DB() gdb.DB { 59 | return g.DB(dao.group) 60 | } 61 | 62 | // Table returns the table name of current dao. 63 | func (dao *AppDao) Table() string { 64 | return dao.table 65 | } 66 | 67 | // Columns returns all column names of current dao. 68 | func (dao *AppDao) Columns() AppColumns { 69 | return dao.columns 70 | } 71 | 72 | // Group returns the configuration group name of database of current dao. 73 | func (dao *AppDao) Group() string { 74 | return dao.group 75 | } 76 | 77 | // Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. 78 | func (dao *AppDao) Ctx(ctx context.Context) *gdb.Model { 79 | return dao.DB().Model(dao.table).Safe().Ctx(ctx) 80 | } 81 | 82 | // Transaction wraps the transaction logic using function f. 83 | // It rollbacks the transaction and returns the error from function f if it returns non-nil error. 84 | // It commits the transaction and returns nil if function f returns nil. 85 | // 86 | // Note that, you should not Commit or Rollback the transaction in function f 87 | // as it is automatically handled by this function. 88 | func (dao *AppDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { 89 | return dao.Ctx(ctx).Transaction(ctx, f) 90 | } 91 | -------------------------------------------------------------------------------- /internal/service/internal/dao/internal/check_tpl.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "context" 9 | "github.com/gogf/gf/v2/database/gdb" 10 | "github.com/gogf/gf/v2/frame/g" 11 | ) 12 | 13 | // CheckTplDao is the data access object for table check_tpl. 14 | type CheckTplDao struct { 15 | table string // table is the underlying table name of the DAO. 16 | group string // group is the database configuration group name of current DAO. 17 | columns CheckTplColumns // columns contains all the column names of Table for convenient usage. 18 | } 19 | 20 | // CheckTplColumns defines and stores column names for table check_tpl. 21 | type CheckTplColumns struct { 22 | Id string // 23 | Tid string // 唯一id 24 | Name string // 名称 25 | Description string // 描述 26 | Type string // 类型 27 | Creater string // 创建人 28 | Updater string // 更新人 29 | Created string // 30 | Updated string // 31 | } 32 | 33 | // checkTplColumns holds the columns for table check_tpl. 34 | var checkTplColumns = CheckTplColumns{ 35 | Id: "id", 36 | Tid: "tid", 37 | Name: "name", 38 | Description: "description", 39 | Type: "type", 40 | Creater: "creater", 41 | Updater: "updater", 42 | Created: "created", 43 | Updated: "updated", 44 | } 45 | 46 | // NewCheckTplDao creates and returns a new DAO object for table data access. 47 | func NewCheckTplDao() *CheckTplDao { 48 | return &CheckTplDao{ 49 | group: "default", 50 | table: "check_tpl", 51 | columns: checkTplColumns, 52 | } 53 | } 54 | 55 | // DB retrieves and returns the underlying raw database management object of current DAO. 56 | func (dao *CheckTplDao) DB() gdb.DB { 57 | return g.DB(dao.group) 58 | } 59 | 60 | // Table returns the table name of current dao. 61 | func (dao *CheckTplDao) Table() string { 62 | return dao.table 63 | } 64 | 65 | // Columns returns all column names of current dao. 66 | func (dao *CheckTplDao) Columns() CheckTplColumns { 67 | return dao.columns 68 | } 69 | 70 | // Group returns the configuration group name of database of current dao. 71 | func (dao *CheckTplDao) Group() string { 72 | return dao.group 73 | } 74 | 75 | // Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. 76 | func (dao *CheckTplDao) Ctx(ctx context.Context) *gdb.Model { 77 | return dao.DB().Model(dao.table).Safe().Ctx(ctx) 78 | } 79 | 80 | // Transaction wraps the transaction logic using function f. 81 | // It rollbacks the transaction and returns the error from function f if it returns non-nil error. 82 | // It commits the transaction and returns nil if function f returns nil. 83 | // 84 | // Note that, you should not Commit or Rollback the transaction in function f 85 | // as it is automatically handled by this function. 86 | func (dao *CheckTplDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { 87 | return dao.Ctx(ctx).Transaction(ctx, f) 88 | } 89 | -------------------------------------------------------------------------------- /internal/service/internal/dao/internal/check_tpl_detail.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "context" 9 | "github.com/gogf/gf/v2/database/gdb" 10 | "github.com/gogf/gf/v2/frame/g" 11 | ) 12 | 13 | // CheckTplDetailDao is the data access object for table check_tpl_detail. 14 | type CheckTplDetailDao struct { 15 | table string // table is the underlying table name of the DAO. 16 | group string // group is the database configuration group name of current DAO. 17 | columns CheckTplDetailColumns // columns contains all the column names of Table for convenient usage. 18 | } 19 | 20 | // CheckTplDetailColumns defines and stores column names for table check_tpl_detail. 21 | type CheckTplDetailColumns struct { 22 | Id string // 23 | Tid string // 模板id 24 | Cid string // 检查项id 25 | Sort string // 排序 26 | Weight string // 权重 27 | } 28 | 29 | // checkTplDetailColumns holds the columns for table check_tpl_detail. 30 | var checkTplDetailColumns = CheckTplDetailColumns{ 31 | Id: "id", 32 | Tid: "tid", 33 | Cid: "cid", 34 | Sort: "sort", 35 | Weight: "weight", 36 | } 37 | 38 | // NewCheckTplDetailDao creates and returns a new DAO object for table data access. 39 | func NewCheckTplDetailDao() *CheckTplDetailDao { 40 | return &CheckTplDetailDao{ 41 | group: "default", 42 | table: "check_tpl_detail", 43 | columns: checkTplDetailColumns, 44 | } 45 | } 46 | 47 | // DB retrieves and returns the underlying raw database management object of current DAO. 48 | func (dao *CheckTplDetailDao) DB() gdb.DB { 49 | return g.DB(dao.group) 50 | } 51 | 52 | // Table returns the table name of current dao. 53 | func (dao *CheckTplDetailDao) Table() string { 54 | return dao.table 55 | } 56 | 57 | // Columns returns all column names of current dao. 58 | func (dao *CheckTplDetailDao) Columns() CheckTplDetailColumns { 59 | return dao.columns 60 | } 61 | 62 | // Group returns the configuration group name of database of current dao. 63 | func (dao *CheckTplDetailDao) Group() string { 64 | return dao.group 65 | } 66 | 67 | // Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. 68 | func (dao *CheckTplDetailDao) Ctx(ctx context.Context) *gdb.Model { 69 | return dao.DB().Model(dao.table).Safe().Ctx(ctx) 70 | } 71 | 72 | // Transaction wraps the transaction logic using function f. 73 | // It rollbacks the transaction and returns the error from function f if it returns non-nil error. 74 | // It commits the transaction and returns nil if function f returns nil. 75 | // 76 | // Note that, you should not Commit or Rollback the transaction in function f 77 | // as it is automatically handled by this function. 78 | func (dao *CheckTplDetailDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { 79 | return dao.Ctx(ctx).Transaction(ctx, f) 80 | } 81 | -------------------------------------------------------------------------------- /internal/service/internal/dao/internal/plugin.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "context" 9 | "github.com/gogf/gf/v2/database/gdb" 10 | "github.com/gogf/gf/v2/frame/g" 11 | ) 12 | 13 | // PluginDao is the data access object for table plugin. 14 | type PluginDao struct { 15 | table string // table is the underlying table name of the DAO. 16 | group string // group is the database configuration group name of current DAO. 17 | columns PluginColumns // columns contains all the column names of Table for convenient usage. 18 | } 19 | 20 | // PluginColumns defines and stores column names for table plugin. 21 | type PluginColumns struct { 22 | Id string // 23 | Uuid string // 插件uuid 24 | Name string // 插件名 25 | PackageName string // 包名 26 | Os string // 操作系统 27 | Arch string // 架构 28 | Md5 string // 包md5名称 29 | Creater string // 创建人 30 | Updater string // 更新人 31 | Created string // 32 | Updated string // 33 | } 34 | 35 | // pluginColumns holds the columns for table plugin. 36 | var pluginColumns = PluginColumns{ 37 | Id: "id", 38 | Uuid: "uuid", 39 | Name: "name", 40 | PackageName: "package_name", 41 | Os: "os", 42 | Arch: "arch", 43 | Md5: "md5", 44 | Creater: "creater", 45 | Updater: "updater", 46 | Created: "created", 47 | Updated: "updated", 48 | } 49 | 50 | // NewPluginDao creates and returns a new DAO object for table data access. 51 | func NewPluginDao() *PluginDao { 52 | return &PluginDao{ 53 | group: "default", 54 | table: "plugin", 55 | columns: pluginColumns, 56 | } 57 | } 58 | 59 | // DB retrieves and returns the underlying raw database management object of current DAO. 60 | func (dao *PluginDao) DB() gdb.DB { 61 | return g.DB(dao.group) 62 | } 63 | 64 | // Table returns the table name of current dao. 65 | func (dao *PluginDao) Table() string { 66 | return dao.table 67 | } 68 | 69 | // Columns returns all column names of current dao. 70 | func (dao *PluginDao) Columns() PluginColumns { 71 | return dao.columns 72 | } 73 | 74 | // Group returns the configuration group name of database of current dao. 75 | func (dao *PluginDao) Group() string { 76 | return dao.group 77 | } 78 | 79 | // Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. 80 | func (dao *PluginDao) Ctx(ctx context.Context) *gdb.Model { 81 | return dao.DB().Model(dao.table).Safe().Ctx(ctx) 82 | } 83 | 84 | // Transaction wraps the transaction logic using function f. 85 | // It rollbacks the transaction and returns the error from function f if it returns non-nil error. 86 | // It commits the transaction and returns nil if function f returns nil. 87 | // 88 | // Note that, you should not Commit or Rollback the transaction in function f 89 | // as it is automatically handled by this function. 90 | func (dao *PluginDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { 91 | return dao.Ctx(ctx).Transaction(ctx, f) 92 | } 93 | -------------------------------------------------------------------------------- /internal/service/internal/dao/internal/task.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "context" 9 | "github.com/gogf/gf/v2/database/gdb" 10 | "github.com/gogf/gf/v2/frame/g" 11 | ) 12 | 13 | // TaskDao is the data access object for table task. 14 | type TaskDao struct { 15 | table string // table is the underlying table name of the DAO. 16 | group string // group is the database configuration group name of current DAO. 17 | columns TaskColumns // columns contains all the column names of Table for convenient usage. 18 | } 19 | 20 | // TaskColumns defines and stores column names for table task. 21 | type TaskColumns struct { 22 | Id string // 23 | TaskId string // 任务id 24 | Type string // 任务类型 25 | Content string // 任务内容 26 | Name string // 任务名称 27 | Reqid string // 请求id 28 | ParentId string // 29 | Status string // 30 | Created string // 31 | Updated string // 32 | Creater string // 创建人 33 | } 34 | 35 | // taskColumns holds the columns for table task. 36 | var taskColumns = TaskColumns{ 37 | Id: "id", 38 | TaskId: "task_id", 39 | Type: "type", 40 | Content: "content", 41 | Name: "name", 42 | Reqid: "reqid", 43 | ParentId: "parent_id", 44 | Status: "status", 45 | Created: "created", 46 | Updated: "updated", 47 | Creater: "creater", 48 | } 49 | 50 | // NewTaskDao creates and returns a new DAO object for table data access. 51 | func NewTaskDao() *TaskDao { 52 | return &TaskDao{ 53 | group: "default", 54 | table: "task", 55 | columns: taskColumns, 56 | } 57 | } 58 | 59 | // DB retrieves and returns the underlying raw database management object of current DAO. 60 | func (dao *TaskDao) DB() gdb.DB { 61 | return g.DB(dao.group) 62 | } 63 | 64 | // Table returns the table name of current dao. 65 | func (dao *TaskDao) Table() string { 66 | return dao.table 67 | } 68 | 69 | // Columns returns all column names of current dao. 70 | func (dao *TaskDao) Columns() TaskColumns { 71 | return dao.columns 72 | } 73 | 74 | // Group returns the configuration group name of database of current dao. 75 | func (dao *TaskDao) Group() string { 76 | return dao.group 77 | } 78 | 79 | // Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. 80 | func (dao *TaskDao) Ctx(ctx context.Context) *gdb.Model { 81 | return dao.DB().Model(dao.table).Safe().Ctx(ctx) 82 | } 83 | 84 | // Transaction wraps the transaction logic using function f. 85 | // It rollbacks the transaction and returns the error from function f if it returns non-nil error. 86 | // It commits the transaction and returns nil if function f returns nil. 87 | // 88 | // Note that, you should not Commit or Rollback the transaction in function f 89 | // as it is automatically handled by this function. 90 | func (dao *TaskDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { 91 | return dao.Ctx(ctx).Transaction(ctx, f) 92 | } 93 | -------------------------------------------------------------------------------- /internal/service/internal/dao/internal/task_preset.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "context" 9 | "github.com/gogf/gf/v2/database/gdb" 10 | "github.com/gogf/gf/v2/frame/g" 11 | ) 12 | 13 | // TaskPresetDao is the data access object for table task_preset. 14 | type TaskPresetDao struct { 15 | table string // table is the underlying table name of the DAO. 16 | group string // group is the database configuration group name of current DAO. 17 | columns TaskPresetColumns // columns contains all the column names of Table for convenient usage. 18 | } 19 | 20 | // TaskPresetColumns defines and stores column names for table task_preset. 21 | type TaskPresetColumns struct { 22 | Id string // 23 | Uuid string // 24 | Name string // 任务名 25 | Type string // 任务类型 26 | Content string // 任务内容 27 | Peers string // 主机列表 28 | Creater string // 创建人 29 | Created string // 创建时间 30 | Updated string // 更新时间 31 | Updater string // 更新人 32 | } 33 | 34 | // taskPresetColumns holds the columns for table task_preset. 35 | var taskPresetColumns = TaskPresetColumns{ 36 | Id: "id", 37 | Uuid: "uuid", 38 | Name: "name", 39 | Type: "type", 40 | Content: "content", 41 | Peers: "peers", 42 | Creater: "creater", 43 | Created: "created", 44 | Updated: "updated", 45 | Updater: "updater", 46 | } 47 | 48 | // NewTaskPresetDao creates and returns a new DAO object for table data access. 49 | func NewTaskPresetDao() *TaskPresetDao { 50 | return &TaskPresetDao{ 51 | group: "default", 52 | table: "task_preset", 53 | columns: taskPresetColumns, 54 | } 55 | } 56 | 57 | // DB retrieves and returns the underlying raw database management object of current DAO. 58 | func (dao *TaskPresetDao) DB() gdb.DB { 59 | return g.DB(dao.group) 60 | } 61 | 62 | // Table returns the table name of current dao. 63 | func (dao *TaskPresetDao) Table() string { 64 | return dao.table 65 | } 66 | 67 | // Columns returns all column names of current dao. 68 | func (dao *TaskPresetDao) Columns() TaskPresetColumns { 69 | return dao.columns 70 | } 71 | 72 | // Group returns the configuration group name of database of current dao. 73 | func (dao *TaskPresetDao) Group() string { 74 | return dao.group 75 | } 76 | 77 | // Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. 78 | func (dao *TaskPresetDao) Ctx(ctx context.Context) *gdb.Model { 79 | return dao.DB().Model(dao.table).Safe().Ctx(ctx) 80 | } 81 | 82 | // Transaction wraps the transaction logic using function f. 83 | // It rollbacks the transaction and returns the error from function f if it returns non-nil error. 84 | // It commits the transaction and returns nil if function f returns nil. 85 | // 86 | // Note that, you should not Commit or Rollback the transaction in function f 87 | // as it is automatically handled by this function. 88 | func (dao *TaskPresetDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { 89 | return dao.Ctx(ctx).Transaction(ctx, f) 90 | } 91 | -------------------------------------------------------------------------------- /internal/service/internal/dao/internal/user.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "context" 9 | "github.com/gogf/gf/v2/database/gdb" 10 | "github.com/gogf/gf/v2/frame/g" 11 | ) 12 | 13 | // UserDao is the data access object for table user. 14 | type UserDao struct { 15 | table string // table is the underlying table name of the DAO. 16 | group string // group is the database configuration group name of current DAO. 17 | columns UserColumns // columns contains all the column names of Table for convenient usage. 18 | } 19 | 20 | // UserColumns defines and stores column names for table user. 21 | type UserColumns struct { 22 | Id string // 23 | Uid string // 24 | Username string // 25 | Passwd string // 26 | Email string // 27 | Created string // 28 | Updated string // 29 | Phone string // 30 | Avatar string // 头像 31 | Status string // 状态 1 启用 2 禁用 32 | } 33 | 34 | // userColumns holds the columns for table user. 35 | var userColumns = UserColumns{ 36 | Id: "id", 37 | Uid: "uid", 38 | Username: "username", 39 | Passwd: "passwd", 40 | Email: "email", 41 | Created: "created", 42 | Updated: "updated", 43 | Phone: "phone", 44 | Avatar: "avatar", 45 | Status: "status", 46 | } 47 | 48 | // NewUserDao creates and returns a new DAO object for table data access. 49 | func NewUserDao() *UserDao { 50 | return &UserDao{ 51 | group: "default", 52 | table: "user", 53 | columns: userColumns, 54 | } 55 | } 56 | 57 | // DB retrieves and returns the underlying raw database management object of current DAO. 58 | func (dao *UserDao) DB() gdb.DB { 59 | return g.DB(dao.group) 60 | } 61 | 62 | // Table returns the table name of current dao. 63 | func (dao *UserDao) Table() string { 64 | return dao.table 65 | } 66 | 67 | // Columns returns all column names of current dao. 68 | func (dao *UserDao) Columns() UserColumns { 69 | return dao.columns 70 | } 71 | 72 | // Group returns the configuration group name of database of current dao. 73 | func (dao *UserDao) Group() string { 74 | return dao.group 75 | } 76 | 77 | // Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. 78 | func (dao *UserDao) Ctx(ctx context.Context) *gdb.Model { 79 | return dao.DB().Model(dao.table).Safe().Ctx(ctx) 80 | } 81 | 82 | // Transaction wraps the transaction logic using function f. 83 | // It rollbacks the transaction and returns the error from function f if it returns non-nil error. 84 | // It commits the transaction and returns nil if function f returns nil. 85 | // 86 | // Note that, you should not Commit or Rollback the transaction in function f 87 | // as it is automatically handled by this function. 88 | func (dao *UserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { 89 | return dao.Ctx(ctx).Transaction(ctx, f) 90 | } 91 | -------------------------------------------------------------------------------- /internal/service/internal/dao/plugin.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalPluginDao is internal type for wrapping internal DAO implements. 12 | type internalPluginDao = *internal.PluginDao 13 | 14 | // pluginDao is the data access object for table plugin. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type pluginDao struct { 17 | internalPluginDao 18 | } 19 | 20 | var ( 21 | // Plugin is globally public accessible object for table plugin operations. 22 | Plugin = pluginDao{ 23 | internal.NewPluginDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/script.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalScriptDao is internal type for wrapping internal DAO implements. 12 | type internalScriptDao = *internal.ScriptDao 13 | 14 | // scriptDao is the data access object for table script. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type scriptDao struct { 17 | internalScriptDao 18 | } 19 | 20 | var ( 21 | // Script is globally public accessible object for table script operations. 22 | Script = scriptDao{ 23 | internal.NewScriptDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/task.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalTaskDao is internal type for wrapping internal DAO implements. 12 | type internalTaskDao = *internal.TaskDao 13 | 14 | // taskDao is the data access object for table task. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type taskDao struct { 17 | internalTaskDao 18 | } 19 | 20 | var ( 21 | // Task is globally public accessible object for table task operations. 22 | Task = taskDao{ 23 | internal.NewTaskDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/task_preset.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalTaskPresetDao is internal type for wrapping internal DAO implements. 12 | type internalTaskPresetDao = *internal.TaskPresetDao 13 | 14 | // taskPresetDao is the data access object for table task_preset. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type taskPresetDao struct { 17 | internalTaskPresetDao 18 | } 19 | 20 | var ( 21 | // TaskPreset is globally public accessible object for table task_preset operations. 22 | TaskPreset = taskPresetDao{ 23 | internal.NewTaskPresetDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/user.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalUserDao is internal type for wrapping internal DAO implements. 12 | type internalUserDao = *internal.UserDao 13 | 14 | // userDao is the data access object for table user. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type userDao struct { 17 | internalUserDao 18 | } 19 | 20 | var ( 21 | // User is globally public accessible object for table user operations. 22 | User = userDao{ 23 | internal.NewUserDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/dao/vm.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. 3 | // ================================================================================= 4 | 5 | package dao 6 | 7 | import ( 8 | "go-ops/internal/service/internal/dao/internal" 9 | ) 10 | 11 | // internalVmDao is internal type for wrapping internal DAO implements. 12 | type internalVmDao = *internal.VmDao 13 | 14 | // vmDao is the data access object for table vm. 15 | // You can define custom methods on it to extend its functionality as you wish. 16 | type vmDao struct { 17 | internalVmDao 18 | } 19 | 20 | var ( 21 | // Vm is globally public accessible object for table vm operations. 22 | Vm = vmDao{ 23 | internal.NewVmDao(), 24 | } 25 | ) 26 | 27 | // Fill with you ideas below. 28 | -------------------------------------------------------------------------------- /internal/service/internal/do/agent_info.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // AgentInfo is the golang structure of table agent_info for DAO operations like Where/Data. 13 | type AgentInfo struct { 14 | g.Meta `orm:"table:agent_info, do:true"` 15 | Id interface{} // 16 | Peerid interface{} // 节点id 17 | Name interface{} // agent名称 18 | ExpectedStatus interface{} // 期望状态 19 | Status interface{} // 20 | IsDefault interface{} // 21 | Timeout interface{} // 启动超时时间 22 | Created *gtime.Time // 23 | Updated *gtime.Time // 24 | Version interface{} // 版本信息 25 | } 26 | -------------------------------------------------------------------------------- /internal/service/internal/do/app.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // App is the golang structure of table app for DAO operations like Where/Data. 13 | type App struct { 14 | g.Meta `orm:"table:app, do:true"` 15 | Id interface{} // 16 | Appid interface{} // 17 | ApiKey interface{} // 18 | SecKey interface{} // 19 | Owner interface{} // 20 | Name interface{} // 应用名 21 | Status interface{} // 1启用 0 禁用 22 | OwnerUid interface{} // 拥有者uid 23 | CreatedAt *gtime.Time // 24 | UpdatedAt *gtime.Time // 25 | } 26 | -------------------------------------------------------------------------------- /internal/service/internal/do/check_item.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // CheckItem is the golang structure of table check_item for DAO operations like Where/Data. 13 | type CheckItem struct { 14 | g.Meta `orm:"table:check_item, do:true"` 15 | Id interface{} // 16 | CheckItemId interface{} // 17 | Name interface{} // 检查项名称 18 | Desc interface{} // 检查项描述 19 | Type interface{} // 20 | Content interface{} // 检查项内容 21 | Creater interface{} // 创建人 22 | Updater interface{} // 更新人 23 | Created *gtime.Time // 24 | Updated *gtime.Time // 25 | Weight interface{} // 权重 26 | WaitTime interface{} // 超时时间 27 | Cmd interface{} // 脚本执行解释器 28 | } 29 | -------------------------------------------------------------------------------- /internal/service/internal/do/check_tpl.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // CheckTpl is the golang structure of table check_tpl for DAO operations like Where/Data. 13 | type CheckTpl struct { 14 | g.Meta `orm:"table:check_tpl, do:true"` 15 | Id interface{} // 16 | Tid interface{} // 唯一id 17 | Name interface{} // 名称 18 | Description interface{} // 描述 19 | Type interface{} // 类型 20 | Creater interface{} // 创建人 21 | Updater interface{} // 更新人 22 | Created *gtime.Time // 23 | Updated *gtime.Time // 24 | } 25 | -------------------------------------------------------------------------------- /internal/service/internal/do/check_tpl_detail.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | ) 10 | 11 | // CheckTplDetail is the golang structure of table check_tpl_detail for DAO operations like Where/Data. 12 | type CheckTplDetail struct { 13 | g.Meta `orm:"table:check_tpl_detail, do:true"` 14 | Id interface{} // 15 | Tid interface{} // 模板id 16 | Cid interface{} // 检查项id 17 | Sort interface{} // 排序 18 | Weight interface{} // 权重 19 | } 20 | -------------------------------------------------------------------------------- /internal/service/internal/do/cron_task.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // CronTask is the golang structure of table cron_task for DAO operations like Where/Data. 13 | type CronTask struct { 14 | g.Meta `orm:"table:cron_task, do:true"` 15 | Id interface{} // 16 | CronUid interface{} // 17 | Name interface{} // 定时任务名称 18 | Content interface{} // 定时任务内容 19 | CronExpr interface{} // 定时任务表达式 20 | LastrunTime *gtime.Time // 最后执行时间 21 | NextrunTime *gtime.Time // 22 | Status interface{} // 状态 running stopped 23 | Creater interface{} // 创建人 24 | Updater interface{} // 更新人 25 | Created *gtime.Time // 26 | Updated *gtime.Time // 27 | Type interface{} // 任务类型 28 | } 29 | -------------------------------------------------------------------------------- /internal/service/internal/do/plugin.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // Plugin is the golang structure of table plugin for DAO operations like Where/Data. 13 | type Plugin struct { 14 | g.Meta `orm:"table:plugin, do:true"` 15 | Id interface{} // 16 | Uuid interface{} // 插件uuid 17 | Name interface{} // 插件名 18 | PackageName interface{} // 包名 19 | Os interface{} // 操作系统 20 | Arch interface{} // 架构 21 | Md5 interface{} // 包md5名称 22 | Creater interface{} // 创建人 23 | Updater interface{} // 更新人 24 | Created *gtime.Time // 25 | Updated *gtime.Time // 26 | } 27 | -------------------------------------------------------------------------------- /internal/service/internal/do/script.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // Script is the golang structure of table script for DAO operations like Where/Data. 13 | type Script struct { 14 | g.Meta `orm:"table:script, do:true"` 15 | Id interface{} // 16 | Name interface{} // 命令名称 17 | Content interface{} // 脚本内容 18 | Args interface{} // 参数信息 19 | Desc interface{} // 描述信息 20 | Type interface{} // 脚本类型shell或者powershell 21 | OwnerType interface{} // 命令拥有者类型 22 | OwnerUid interface{} // 拥有者uid 23 | Created *gtime.Time // 24 | Updated *gtime.Time // 25 | ScriptUid interface{} // 26 | WaitTime interface{} // 脚本超时时间 27 | Cmd interface{} // 脚本解释器 28 | Ext interface{} // 脚本文件扩展名 29 | } 30 | -------------------------------------------------------------------------------- /internal/service/internal/do/task.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // Task is the golang structure of table task for DAO operations like Where/Data. 13 | type Task struct { 14 | g.Meta `orm:"table:task, do:true"` 15 | Id interface{} // 16 | TaskId interface{} // 任务id 17 | Type interface{} // 任务类型 18 | Content interface{} // 任务内容 19 | Name interface{} // 任务名称 20 | Reqid interface{} // 请求id 21 | ParentId interface{} // 22 | Status interface{} // 23 | Created *gtime.Time // 24 | Updated *gtime.Time // 25 | Creater interface{} // 创建人 26 | } 27 | -------------------------------------------------------------------------------- /internal/service/internal/do/task_preset.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // TaskPreset is the golang structure of table task_preset for DAO operations like Where/Data. 13 | type TaskPreset struct { 14 | g.Meta `orm:"table:task_preset, do:true"` 15 | Id interface{} // 16 | Uuid interface{} // 17 | Name interface{} // 任务名 18 | Type interface{} // 任务类型 19 | Content interface{} // 任务内容 20 | Peers interface{} // 主机列表 21 | Creater interface{} // 创建人 22 | Created *gtime.Time // 创建时间 23 | Updated *gtime.Time // 更新时间 24 | Updater interface{} // 更新人 25 | } 26 | -------------------------------------------------------------------------------- /internal/service/internal/do/user.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // User is the golang structure of table user for DAO operations like Where/Data. 13 | type User struct { 14 | g.Meta `orm:"table:user, do:true"` 15 | Id interface{} // 16 | Uid interface{} // 17 | Username interface{} // 18 | Passwd interface{} // 19 | Email interface{} // 20 | Created *gtime.Time // 21 | Updated *gtime.Time // 22 | Phone interface{} // 23 | Avatar interface{} // 头像 24 | Status interface{} // 状态 1 启用 2 禁用 25 | } 26 | -------------------------------------------------------------------------------- /internal/service/internal/do/vm.go: -------------------------------------------------------------------------------- 1 | // ================================================================================= 2 | // Code generated by GoFrame CLI tool. DO NOT EDIT. 3 | // ================================================================================= 4 | 5 | package do 6 | 7 | import ( 8 | "github.com/gogf/gf/v2/frame/g" 9 | "github.com/gogf/gf/v2/os/gtime" 10 | ) 11 | 12 | // Vm is the golang structure of table vm for DAO operations like Where/Data. 13 | type Vm struct { 14 | g.Meta `orm:"table:vm, do:true"` 15 | Id interface{} // 16 | Uuid interface{} // 主机uuid 17 | Name interface{} // 18 | Hostname interface{} // 19 | OsType interface{} // 操作系统类型 20 | OsInfo interface{} // 操作系统信息 21 | Hosttype interface{} // 主机类型 22 | Networktype interface{} // 网络类型 23 | PrivateIp interface{} // 24 | PublicIp interface{} // 25 | Created *gtime.Time // 26 | Updated *gtime.Time // 27 | Creater interface{} // 创建人 28 | Address interface{} // 29 | PeerId interface{} // 30 | } 31 | -------------------------------------------------------------------------------- /internal/service/user.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | 6 | "go-ops/internal/model/entity" 7 | "go-ops/internal/service/internal/dao" 8 | "go-ops/internal/service/internal/do" 9 | v1 "go-ops/pkg/api/v1" 10 | 11 | "github.com/gogf/gf/v2/errors/gerror" 12 | ) 13 | 14 | type ( 15 | // sUser is service struct of module User. 16 | sUser struct{} 17 | ) 18 | 19 | var ( 20 | // insUser is the instance of service User. 21 | insUser = sUser{} 22 | ) 23 | 24 | // User returns the interface of User service. 25 | func User() *sUser { 26 | return &insUser 27 | } 28 | 29 | func (s *sUser) Get(ctx context.Context, uid string) (r *entity.User, err error) { 30 | err = dao.User.Ctx(ctx).Where("uid = ?", uid).Scan(&r) 31 | if err != nil { 32 | return 33 | } 34 | if r == nil { 35 | return 36 | } 37 | return 38 | } 39 | 40 | func (s *sUser) IsUsernameAvailable(ctx context.Context, username string) (bool, error) { 41 | count, err := dao.User.Ctx(ctx).Where(do.User{ 42 | Username: username, 43 | }).Count() 44 | if err != nil { 45 | return false, err 46 | } 47 | return count == 0, nil 48 | } 49 | 50 | // SignIn creates session for given user account. 51 | func (s *sUser) SignIn(ctx context.Context, in *v1.AuthLoginReq) (r *entity.User, err error) { 52 | var user *entity.User 53 | err = dao.User.Ctx(ctx).Where(do.User{ 54 | Username: in.Username, 55 | Passwd: in.Passwd, 56 | }).Scan(&user) 57 | if err != nil { 58 | return nil, err 59 | } 60 | if user == nil { 61 | return nil, gerror.New(`username or Password not correct`) 62 | } 63 | return user, nil 64 | } 65 | -------------------------------------------------------------------------------- /manifest/config/config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | address: ":8000" 3 | openapiPath: "/api.json" 4 | swaggerPath: "/swagger" 5 | 6 | logger: 7 | level : "all" 8 | stdout: true 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /manifest/deploy/kustomize/base/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: template-single 5 | labels: 6 | app: template-single 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: template-single 12 | template: 13 | metadata: 14 | labels: 15 | app: template-single 16 | spec: 17 | containers: 18 | - name : main 19 | image: template-single 20 | imagePullPolicy: Always 21 | 22 | -------------------------------------------------------------------------------- /manifest/deploy/kustomize/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - deployment.yaml 5 | - service.yaml 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /manifest/deploy/kustomize/base/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: template-single 5 | spec: 6 | ports: 7 | - port: 80 8 | protocol: TCP 9 | targetPort: 8000 10 | selector: 11 | app: template-single 12 | 13 | -------------------------------------------------------------------------------- /manifest/deploy/kustomize/overlays/develop/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: template-single-configmap 5 | data: 6 | config.yaml: | 7 | server: 8 | address: ":8000" 9 | openapiPath: "/api.json" 10 | swaggerPath: "/swagger" 11 | 12 | logger: 13 | level : "all" 14 | stdout: true 15 | -------------------------------------------------------------------------------- /manifest/deploy/kustomize/overlays/develop/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: template-single 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name : main 10 | image: template-single:develop -------------------------------------------------------------------------------- /manifest/deploy/kustomize/overlays/develop/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ../../base 6 | - configmap.yaml 7 | 8 | patchesStrategicMerge: 9 | - deployment.yaml 10 | 11 | namespace: default 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /manifest/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM loads/alpine:3.8 2 | 3 | ############################################################################### 4 | # INSTALLATION 5 | ############################################################################### 6 | 7 | ENV WORKDIR /app 8 | ADD resource $WORKDIR/ 9 | ADD ./temp/linux_amd64/main $WORKDIR/main 10 | RUN chmod +x $WORKDIR/main 11 | 12 | ############################################################################### 13 | # START 14 | ############################################################################### 15 | WORKDIR $WORKDIR 16 | CMD ./main 17 | -------------------------------------------------------------------------------- /manifest/docker/docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This shell is executed before docker build. 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /pkg/agent/action/agent_manager_control.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "context" 5 | "path/filepath" 6 | 7 | "go-ops/internal/model" 8 | "go-ops/pkg/agent/script/cmd" 9 | "go-ops/pkg/errors" 10 | "go-ops/pkg/system" 11 | 12 | "github.com/toolkits/file" 13 | ) 14 | 15 | func control(workdir, args string, timeout int) (stdout string, err error) { 16 | controlScript := getControlName() 17 | cmdRunner := system.NewExecCmdRunner(context.Background()) 18 | 19 | command := cmd.BuildCommand("." + string(filepath.Separator) + controlScript) 20 | command.Args = append(command.Args, args) 21 | 22 | command.Timeout = timeout 23 | command.WorkingDir = workdir 24 | 25 | stdout, stderr, exitCode, _, err := cmdRunner.RunComplexCommand(command) 26 | if stderr != "" { 27 | err = errors.WrapErrorf(err, "stderr:%s \nexitCode:%d", stderr, exitCode) 28 | return 29 | } 30 | 31 | return 32 | } 33 | 34 | func (self *agentManager) workDir(agentName string) (r string) { 35 | return self.agentDir + string(filepath.Separator) + agentName 36 | } 37 | 38 | func (self *agentManager) Start(a *model.AgentInfo) (err error) { 39 | _, err = control(self.workDir(a.Name), "start", a.Timeout) 40 | return 41 | } 42 | 43 | func (self *agentManager) Stop(a *model.AgentInfo) (err error) { 44 | _, err = control(self.workDir(a.Name), "stop", a.Timeout) 45 | return 46 | } 47 | 48 | func (self *agentManager) Status(a *model.AgentInfo) (s string, err error) { 49 | s, err = control(self.workDir(a.Name), "status", a.Timeout) 50 | if err != nil { 51 | return 52 | } 53 | return 54 | } 55 | 56 | func (self *agentManager) Version(a *model.AgentInfo) (s string, err error) { 57 | s, err = control(self.workDir(a.Name), "status", a.Timeout) 58 | if err != nil { 59 | return 60 | } 61 | return 62 | } 63 | 64 | func (self *agentManager) Delete(a *model.AgentInfo) (err error) { 65 | _, err = control(self.workDir(a.Name), "delete", a.Timeout) 66 | if err != nil { 67 | return 68 | } 69 | 70 | return 71 | } 72 | 73 | func (self *agentManager) ControlScriptCheck(a *model.AgentInfo) bool { 74 | if file.IsExist(self.workDir(a.Name) + string(filepath.Separator) + getControlName()) { 75 | return true 76 | } 77 | return false 78 | } 79 | -------------------------------------------------------------------------------- /pkg/agent/action/agent_manager_control_unix.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | func getControlName() string { 4 | return "control" 5 | } 6 | -------------------------------------------------------------------------------- /pkg/agent/action/agent_manager_control_windows.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "os/exec" 5 | "path/filepath" 6 | ) 7 | 8 | func getControlName() string { 9 | return "control.ps1" 10 | } 11 | 12 | func control(workdir, args string) (err error) { 13 | controlScript := getControlName() 14 | 15 | cmd := exec.Command("powershell", "-File", "."+string(filepath.Separator)+controlScript, args) 16 | cmd.Dir = workdir 17 | return cmd.Start() 18 | } 19 | -------------------------------------------------------------------------------- /pkg/agent/action/file_disk.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/model" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | ) 10 | 11 | type fileDisk struct { 12 | } 13 | 14 | func FileDisk() *fileDisk { 15 | return &fileDisk{} 16 | } 17 | 18 | func (self *fileDisk) GetDirInfo(ctx context.Context, spath string) (r []*model.FileInfo, err error) { 19 | infos, err := ioutil.ReadDir(spath) 20 | if err != nil { 21 | return 22 | } 23 | for _, item := range infos { 24 | fi := &model.FileInfo{ 25 | Name: item.Name(), 26 | ModTime: item.ModTime(), 27 | Size: item.Size(), 28 | Path: spath, 29 | } 30 | if item.IsDir() { 31 | fi.Type = "dir" 32 | } else { 33 | fi.Path = filepath.Join(spath, item.Name()) 34 | } 35 | r = append(r, fi) 36 | } 37 | return 38 | } 39 | 40 | func (self *fileDisk) Remove(ctx context.Context, filename string) (err error) { 41 | err = os.Remove(filename) 42 | return 43 | } 44 | 45 | func (self *fileDisk) Move(ctx context.Context, src, dest string) (err error) { 46 | err = os.Rename(src, dest) 47 | return 48 | } 49 | 50 | func (self *fileDisk) CreateDir(ctx context.Context, spath string) (r []*model.FileInfo, err error) { 51 | 52 | if err = os.MkdirAll(spath, os.ModePerm); err != nil { 53 | return 54 | } 55 | 56 | return self.GetDirInfo(ctx, spath) 57 | } 58 | -------------------------------------------------------------------------------- /pkg/agent/action/runner.go: -------------------------------------------------------------------------------- 1 | package action 2 | -------------------------------------------------------------------------------- /pkg/agent/agent_filemanager.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "go-ops/internal/model" 7 | "go-ops/internal/peer" 8 | "go-ops/pkg/agent/action" 9 | "path/filepath" 10 | 11 | "github.com/luxingwen/pnet" 12 | ) 13 | 14 | func (self *OspAgent) ListFileInfo(req *model.PeerListFileInfo, srcId string, msgID []byte, rpath string, pn *pnet.PNet) { 15 | ctx := context.Background() 16 | fileInfos, err := action.FileDisk().GetDirInfo(ctx, req.Path) 17 | if err != nil { 18 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{List: fileInfos, Path: req.Path, Error: err.Error()}, msgID, srcId, rpath) 19 | return 20 | } 21 | 22 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{List: fileInfos, Path: req.Path}, msgID, srcId, rpath) 23 | if err != nil { 24 | fmt.Println("send msg replay err:", err) 25 | } 26 | } 27 | 28 | func (self *OspAgent) MoveFile(req *model.PeerMoveFile, srcId string, msgID []byte, rpath string, pn *pnet.PNet) { 29 | ctx := context.Background() 30 | err := action.FileDisk().Move(ctx, req.Src, req.Dst) 31 | if err != nil { 32 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{Error: err.Error()}, msgID, srcId, rpath) 33 | 34 | return 35 | } 36 | 37 | bpath := filepath.Clean(req.Dst) 38 | 39 | fileInfos, err := action.FileDisk().GetDirInfo(ctx, bpath) 40 | if err != nil { 41 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{Error: err.Error()}, msgID, srcId, rpath) 42 | 43 | return 44 | } 45 | 46 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{List: fileInfos, Path: bpath}, msgID, srcId, rpath) 47 | if err != nil { 48 | fmt.Println("send msg replay err:", err) 49 | } 50 | } 51 | 52 | func (self *OspAgent) CreateDir(req *model.PeerNewDir, srcId string, msgID []byte, rpath string, pn *pnet.PNet) { 53 | ctx := context.Background() 54 | fileInfos, err := action.FileDisk().CreateDir(ctx, req.Path) 55 | if err != nil { 56 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{Error: err.Error()}, msgID, srcId, rpath) 57 | return 58 | } 59 | 60 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{List: fileInfos, Path: req.Path}, msgID, srcId, rpath) 61 | if err != nil { 62 | fmt.Println("send msg replay err:", err) 63 | } 64 | } 65 | 66 | func (self *OspAgent) RemoveFile(req *model.PeerDeleteFile, srcId string, msgID []byte, rpath string, pn *pnet.PNet) { 67 | ctx := context.Background() 68 | err := action.FileDisk().Remove(ctx, req.Path) 69 | if err != nil { 70 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{Error: err.Error()}, msgID, srcId, rpath) 71 | fmt.Println("remove file err:", err) 72 | return 73 | } 74 | 75 | bpath := filepath.Dir(req.Path) 76 | 77 | fileInfos, err := action.FileDisk().GetDirInfo(ctx, bpath) 78 | if err != nil { 79 | fmt.Println("获取文件夹失败:", err) 80 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{Error: err.Error()}, msgID, srcId, rpath) 81 | return 82 | } 83 | 84 | err = peer.SendMsgReplay(pn, &model.PeerListFileInfoRes{List: fileInfos, Path: bpath}, msgID, srcId, rpath) 85 | if err != nil { 86 | fmt.Println("send msg replay err:", err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /pkg/agent/cmd.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "go-ops/internal/peer" 7 | "io/ioutil" 8 | "os" 9 | "time" 10 | 11 | "github.com/luxingwen/pnet/config" 12 | "github.com/luxingwen/pnet/node" 13 | "github.com/shirou/gopsutil/v3/host" 14 | 15 | agentConf "go-ops/pkg/agent/config" 16 | 17 | "github.com/google/uuid" 18 | 19 | log "go-ops/pkg/logger" 20 | ) 21 | 22 | func Main() (err error) { 23 | b, err := ioutil.ReadFile("config.json") 24 | if err != nil { 25 | log.Error("read config.json err:", err) 26 | return 27 | } 28 | 29 | var cfg agentConf.Config 30 | err = json.Unmarshal(b, &cfg) 31 | if err != nil { 32 | log.Error("Unmarshal err:", err) 33 | return 34 | } 35 | 36 | opsAgent := NewOspAgent(&cfg) 37 | 38 | name, err := os.Hostname() 39 | if err != nil { 40 | log.Error("Unmarshal err:", err) 41 | return err 42 | } 43 | 44 | conf := &config.Config{ 45 | Port: uint16(cfg.Port), 46 | Name: name, 47 | } 48 | 49 | id := "" 50 | hid, err := host.HostID() 51 | if err != nil { 52 | id = uuid.New().String() 53 | } else { 54 | id = hid 55 | } 56 | 57 | id = id + "@agent" 58 | 59 | p, err := peer.NewPnet(id, conf, opsAgent.HandlerFunc) 60 | if err != nil { 61 | log.Error("new peer err:", err) 62 | return 63 | } 64 | 65 | err = p.ApplyMiddleware(node.RemoteNodeReady{func(rmoteNode *node.RemoteNode) bool { 66 | peer.SendMsgBroadCast(p, opsAgent.GetPeerInfo(p)) 67 | return true 68 | }, 0}) 69 | 70 | if err != nil { 71 | log.Error("apply middle ware err:", err) 72 | } 73 | 74 | err = p.Start() 75 | if err != nil { 76 | log.Error("peer start err:", err) 77 | return 78 | } 79 | 80 | if len(cfg.Bootlist) == 0 { 81 | log.Error("need join remote peer") 82 | return errors.New("need join remote peer") 83 | } 84 | addr := cfg.Bootlist[0] 85 | 86 | var remoteNode *node.RemoteNode 87 | 88 | for { 89 | remoteNode, err = p.Join(addr) 90 | if err != nil { 91 | log.Errorf("join remote perr: %s err:%v", addr, err) 92 | time.Sleep(time.Second) 93 | continue 94 | } 95 | break 96 | } 97 | 98 | for { 99 | time.Sleep(time.Second) 100 | if remoteNode.IsStopped() { 101 | remoteNode1, err := p.Join(remoteNode.Addr) 102 | if err != nil { 103 | log.Errorf("join remote perr: %s err:%v", addr, err) 104 | } else if remoteNode1 != nil { 105 | remoteNode = remoteNode1 106 | } 107 | } 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /pkg/agent/cmdrunner/cmd_runner.go: -------------------------------------------------------------------------------- 1 | package cmdrunner 2 | 3 | import ( 4 | "go-ops/internal/model" 5 | ospsys "go-ops/pkg/system" 6 | ) 7 | 8 | type CmdResult struct { 9 | Stdout []byte 10 | Stderr []byte 11 | 12 | ExitStatus int 13 | ResCode model.ResCode 14 | } 15 | 16 | type CmdRunner interface { 17 | RunCommand(jobId string, cmd ospsys.Command) (*CmdResult, error) 18 | } 19 | -------------------------------------------------------------------------------- /pkg/agent/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type Config struct { 4 | Port uint32 `json:"port"` 5 | TaskPath string `json:"taskPath"` 6 | Bootlist []string `json:"bootlist"` 7 | } 8 | -------------------------------------------------------------------------------- /pkg/agent/handlermsg.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import ( 4 | "encoding/json" 5 | "go-ops/internal/model" 6 | 7 | "github.com/luxingwen/pnet" 8 | "github.com/luxingwen/pnet/log" 9 | ) 10 | 11 | func (ospAgent *OspAgent) HandlerFunc(msg interface{}, msgID []byte, srcID, rpath string, pn *pnet.PNet) { 12 | switch v := msg.(type) { 13 | case *model.ScriptJob: 14 | ospAgent.CreateScriptTask(v, srcID, msgID, rpath, pn) 15 | case *model.ScriptJobCancel: 16 | ospAgent.CancelcriptTask(v.Jobid, srcID, msgID, rpath, pn) 17 | case *model.GetTaskInfo: 18 | ospAgent.GetTaskInfo(v.TaskId, srcID, msgID, rpath, pn) 19 | case *model.DownloadFileJob: 20 | ospAgent.DownloadFile(v, srcID, msgID, rpath, pn) 21 | case *model.PeerListFileInfo: 22 | ospAgent.ListFileInfo(v, srcID, msgID, rpath, pn) 23 | case *model.PeerMoveFile: 24 | ospAgent.MoveFile(v, srcID, msgID, rpath, pn) 25 | case *model.PeerNewDir: 26 | ospAgent.CreateDir(v, srcID, msgID, rpath, pn) 27 | case *model.PeerDeleteFile: 28 | ospAgent.RemoveFile(v, srcID, msgID, rpath, pn) 29 | case *model.GetPeerInfo: 30 | ospAgent.FineAgentByHostname(v, srcID, msgID, rpath, pn) 31 | default: 32 | b, _ := json.Marshal(v) 33 | log.Error("msg handler not found,msg: %s", string(b)) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pkg/agent/script/cmd/build_cmd_unix.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | ospenv "go-ops/pkg/agent/script/pathenv" 5 | ospsys "go-ops/pkg/system" 6 | ) 7 | 8 | func BuildCommand(path string) ospsys.Command { 9 | return ospsys.Command{ 10 | Name: path, 11 | Env: map[string]string{ 12 | "PATH": ospenv.Path(), 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pkg/agent/script/cmd/build_cmd_windows.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | ospenv "go-ops/pkg/agent/script/pathenv" 5 | ospsys "go-ops/pkg/system" 6 | ) 7 | 8 | func BuildCommand(path string) ospsys.Command { 9 | return ospsys.Command{ 10 | Name: "powershell", 11 | Args: []string{path}, 12 | Env: map[string]string{ 13 | "PATH": ospenv.Path(), 14 | }, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pkg/agent/script/content_script.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "go-ops/internal/model" 5 | "go-ops/pkg/agent/cmdrunner" 6 | "os" 7 | 8 | "go-ops/pkg/agent/script/cmd" 9 | "path" 10 | "strings" 11 | ) 12 | 13 | type ContentScript struct { 14 | GenericScript 15 | cmd string 16 | input string 17 | ext string 18 | } 19 | 20 | func NewContentScript( 21 | runner cmdrunner.CmdRunner, 22 | jobid string, 23 | path string, 24 | cmd string, 25 | content string, 26 | env map[string]string, 27 | timeout int, 28 | input string, 29 | user string, 30 | args []string, 31 | ext string, 32 | ) ContentScript { 33 | 34 | if cmd == "" { 35 | cmd = Cmder 36 | } 37 | 38 | s := ContentScript{cmd: cmd, input: input, ext: ext} 39 | s.GenericScript.runner = runner 40 | s.GenericScript.path = path 41 | s.GenericScript.content = content 42 | s.GenericScript.env = env 43 | s.GenericScript.jobid = jobid 44 | s.GenericScript.timeout = timeout 45 | s.GenericScript.user = user 46 | s.GenericScript.args = args 47 | 48 | return s 49 | } 50 | 51 | func (s ContentScript) Run() (r model.ResCmd) { 52 | 53 | if s.path == "" { 54 | s.path = ScriptPath 55 | } 56 | runpath := path.Join(s.path, s.jobid+s.ext) 57 | err := s.ensureContainingDir(runpath) 58 | 59 | if err != nil { 60 | return s.getResCmd(nil, err) 61 | } 62 | 63 | f, err := os.OpenFile(runpath, fileOpenFlag, fileOpenPerm) 64 | if err != nil { 65 | return 66 | } 67 | defer f.Close() 68 | 69 | _, err = f.WriteString(s.content) 70 | if err != nil { 71 | return 72 | } 73 | err = f.Close() 74 | if err != nil { 75 | return 76 | } 77 | 78 | cmdstr, args := getCmdArgs(s.cmd) 79 | 80 | command := cmd.BuildCommand(cmdstr) 81 | 82 | command.Args = append(command.Args, args...) 83 | command.Args = append(command.Args, runpath) 84 | command.Args = append(command.Args, s.args...) 85 | command.Timeout = s.timeout 86 | command.User = s.user 87 | command.WorkingDir = s.path 88 | 89 | if s.input != "" { 90 | command.Stdin = strings.NewReader(s.input) 91 | } 92 | 93 | for key, val := range s.env { 94 | command.Env[key] = val 95 | } 96 | 97 | res, err := s.runner.RunCommand(s.jobid, command) 98 | return s.getResCmd(res, err) 99 | } 100 | -------------------------------------------------------------------------------- /pkg/agent/script/content_script_test.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "go-ops/internal/model" 7 | 8 | "testing" 9 | 10 | "github.com/gogf/gf/v2/util/guid" 11 | ) 12 | 13 | func testGetContentScriptJob(content, spath string) model.ScriptJob { 14 | s := model.Script{ 15 | Content: content, 16 | Path: spath, 17 | ExecWay: model.ExecContent, 18 | Ext: ".sh", 19 | } 20 | s1 := model.ScriptJob{ 21 | Jobid: guid.S(), 22 | Script: s, 23 | } 24 | return s1 25 | } 26 | 27 | func TestContentGenericScript(t *testing.T) { 28 | // s := testGetScriptJob("ls", "") 29 | ctx, _ := context.WithCancel(context.Background()) 30 | // res := NewJobScriptProvider(ctx, s).Run() 31 | 32 | s := testGetContentScriptJob("echo $HOME", "") 33 | res := NewJobScriptProvider(ctx, s).Run() 34 | fmt.Println("res:", res) 35 | } 36 | -------------------------------------------------------------------------------- /pkg/agent/script/ext_unix.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | const ScriptExt = "" 4 | 5 | const Cmder = "/bin/sh" 6 | 7 | const ScriptPath = "/tmp/go-ops/script" 8 | -------------------------------------------------------------------------------- /pkg/agent/script/ext_windows.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | const ScriptExt = ".ps1" 4 | 5 | const Cmder = "powershell" 6 | 7 | const ScriptPath = "/tmp/go-ops/script" 8 | -------------------------------------------------------------------------------- /pkg/agent/script/generic_script.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | "github.com/charlievieth/fs" 8 | 9 | "go-ops/internal/model" 10 | "go-ops/pkg/agent/cmdrunner" 11 | "go-ops/pkg/agent/script/cmd" 12 | ) 13 | 14 | const ( 15 | fileOpenFlag int = os.O_RDWR | os.O_CREATE | os.O_TRUNC 16 | fileOpenPerm os.FileMode = os.FileMode(0777) 17 | ) 18 | 19 | type ExecType int 20 | 21 | const ( 22 | ExecCmd ExecType = iota // 直接命令执行 23 | ExecContent // 需要解释器 内容保存在一个文件脚本里面执行 24 | ExecScript // 需要解释器 脚本就在本地 25 | ExecURL // 脚本从云端下载 26 | ) 27 | 28 | type GenericScript struct { 29 | runner cmdrunner.CmdRunner 30 | path string 31 | content string 32 | args []string 33 | jobid string 34 | env map[string]string 35 | timeout int 36 | user string 37 | } 38 | 39 | func NewScript( 40 | runner cmdrunner.CmdRunner, 41 | jobid string, 42 | path string, 43 | content string, 44 | env map[string]string, 45 | timeout int, 46 | user string, 47 | args []string, 48 | ) GenericScript { 49 | return GenericScript{ 50 | runner: runner, 51 | path: path, 52 | content: content, 53 | env: env, 54 | jobid: jobid, 55 | timeout: timeout, 56 | user: user, 57 | args: args, 58 | } 59 | } 60 | 61 | func (s GenericScript) Path() string { return s.path } 62 | 63 | func (s GenericScript) Run() (r model.ResCmd) { 64 | cmdstr, args := getCmdArgs(s.content) 65 | command := cmd.BuildCommand(cmdstr) 66 | for key, val := range s.env { 67 | command.Env[key] = val 68 | } 69 | 70 | command.Args = append(command.Args, args...) 71 | command.Timeout = s.timeout 72 | command.User = s.user 73 | command.WorkingDir = s.path 74 | 75 | res, err := s.runner.RunCommand(s.jobid, command) 76 | return s.getResCmd(res, err) 77 | } 78 | 79 | func (s GenericScript) getResCmd(res *cmdrunner.CmdResult, err error) (r model.ResCmd) { 80 | if err != nil { 81 | r.Code = model.CodeNotRun 82 | r.Err = err.Error() 83 | r.ExitCode = -1 84 | return 85 | } 86 | r = model.ResCmd{ 87 | Stdout: string(res.Stdout), 88 | Stderr: string(res.Stderr), 89 | ExitCode: res.ExitStatus, 90 | } 91 | 92 | if res.ResCode != "" { 93 | r.Code = res.ResCode 94 | return 95 | } 96 | 97 | if r.ExitCode == 0 { 98 | r.Code = model.CodeSuccess 99 | } else { 100 | r.Code = model.CodeFailed 101 | } 102 | return 103 | } 104 | 105 | func (s GenericScript) ensureContainingDir(fullLogFilename string) error { 106 | dir, _ := filepath.Split(fullLogFilename) 107 | return fs.MkdirAll(dir, os.FileMode(0750)) 108 | } 109 | -------------------------------------------------------------------------------- /pkg/agent/script/generic_script_test.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "go-ops/internal/model" 7 | 8 | "testing" 9 | 10 | "github.com/gogf/gf/v2/util/guid" 11 | ) 12 | 13 | func testGetScriptJob(content, spath string) model.ScriptJob { 14 | s := model.Script{ 15 | Content: content, 16 | Path: spath, 17 | } 18 | s1 := model.ScriptJob{ 19 | Jobid: guid.S(), 20 | Script: s, 21 | } 22 | return s1 23 | } 24 | 25 | func TestGenericScript(t *testing.T) { 26 | s := testGetScriptJob("ls", "") 27 | ctx, _ := context.WithCancel(context.Background()) 28 | res := NewJobScriptProvider(ctx, s).Run() 29 | 30 | fmt.Println("res0:", res) 31 | 32 | s = testGetScriptJob("pwd", "") 33 | res = NewJobScriptProvider(ctx, s).Run() 34 | fmt.Println("res1:", res) 35 | 36 | s = testGetScriptJob("pwd", "/home/lewis/go/src/go-ops/pkg/agent/script") 37 | res = NewJobScriptProvider(ctx, s).Run() 38 | fmt.Println("res2:", res) 39 | 40 | s = testGetScriptJob("ls", "/home/lewis/go/src/go-ops/pkg/agent/script") 41 | res = NewJobScriptProvider(ctx, s).Run() 42 | fmt.Println("res3:", res) 43 | 44 | s = testGetScriptJob("echo $HOME", "") 45 | res = NewJobScriptProvider(ctx, s).Run() 46 | fmt.Println("res4:", res) 47 | } 48 | -------------------------------------------------------------------------------- /pkg/agent/script/job_script.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/model" 6 | "go-ops/pkg/agent/cmdrunner" 7 | ospsys "go-ops/pkg/system" 8 | "os" 9 | "strings" 10 | 11 | log "go-ops/pkg/logger" 12 | ) 13 | 14 | type JobScriptProvider struct { 15 | cmdRunner cmdrunner.CmdRunner 16 | scripter Script 17 | } 18 | 19 | func NewJobScriptProvider( 20 | ctx context.Context, 21 | scriptJob model.ScriptJob, 22 | ) JobScriptProvider { 23 | path := scriptJob.Script.Path 24 | if path == "" { 25 | path = ScriptPath + "/" + scriptJob.Jobid 26 | } 27 | runer := cmdrunner.NewScriptCmdRunner(ospsys.NewExecCmdRunner(ctx), ScriptPath) 28 | p := JobScriptProvider{ 29 | cmdRunner: runer, 30 | } 31 | 32 | // 如果文件得扩展名不是以.结尾 33 | if scriptJob.Script.Ext != "" && !strings.HasPrefix(scriptJob.Script.Ext, ".") { 34 | scriptJob.Script.Ext = "." + scriptJob.Script.Ext 35 | } 36 | 37 | if scriptJob.Script.Ext == "" { 38 | scriptJob.Script.Ext = ScriptExt 39 | } 40 | 41 | log.Infof("[%s] new script job, execway: %v, waitime:%d", scriptJob.Jobid, scriptJob.Script.ExecWay, scriptJob.Script.Timeout) 42 | 43 | switch scriptJob.Script.ExecWay { 44 | case model.ExecCmd: 45 | p.scripter = NewScript(runer, scriptJob.Jobid, path, scriptJob.Script.Content, scriptJob.Script.Env, scriptJob.Script.Timeout, scriptJob.Script.User, scriptJob.Script.Args) 46 | case model.ExecContent: 47 | p.scripter = NewContentScript(runer, scriptJob.Jobid, path, scriptJob.Script.Cmd, scriptJob.Script.Content, scriptJob.Script.Env, 48 | scriptJob.Script.Timeout, scriptJob.Script.Input, scriptJob.Script.User, scriptJob.Script.Args, scriptJob.Script.Ext) 49 | case model.ExecScriptName: 50 | p.scripter = NewNameScript(runer, scriptJob.Jobid, path, scriptJob.Script.Cmd, scriptJob.Script.Content, scriptJob.Script.Env, scriptJob.Script.Timeout, scriptJob.Script.Input, scriptJob.Script.User, scriptJob.Script.Args) 51 | case model.ExecURL: 52 | p.scripter = NewUrlScript(runer, scriptJob.Jobid, path, scriptJob.Script.Cmd, scriptJob.Script.Content, scriptJob.Script.Env, scriptJob.Script.Timeout, scriptJob.Script.User, scriptJob.Script.Args, scriptJob.Script.Input) 53 | 54 | } 55 | return p 56 | } 57 | 58 | func (p JobScriptProvider) Run() model.ResCmd { 59 | return p.scripter.Run() 60 | } 61 | 62 | func getCmdArgs(s string) (cmd string, args []string) { 63 | s = os.ExpandEnv(s) 64 | list := strings.Fields(s) 65 | if len(list) <= 0 { 66 | return 67 | } 68 | if len(list) == 1 { 69 | cmd = list[0] 70 | return 71 | } 72 | 73 | cmd = list[0] 74 | args = list[1:] 75 | return 76 | 77 | } 78 | -------------------------------------------------------------------------------- /pkg/agent/script/name_script.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "go-ops/internal/model" 5 | "go-ops/pkg/agent/cmdrunner" 6 | "go-ops/pkg/agent/script/cmd" 7 | "strings" 8 | ) 9 | 10 | type NameScript struct { 11 | GenericScript 12 | cmd string 13 | input string 14 | } 15 | 16 | func NewNameScript( 17 | runner cmdrunner.CmdRunner, 18 | jobid string, 19 | path string, 20 | cmd string, 21 | content string, 22 | env map[string]string, 23 | timeout int, 24 | input string, 25 | user string, 26 | args []string, 27 | ) NameScript { 28 | 29 | if cmd == "" { 30 | cmd = Cmder 31 | } 32 | 33 | s := NameScript{cmd: cmd, input: input} 34 | s.GenericScript.runner = runner 35 | s.GenericScript.path = path 36 | s.GenericScript.content = content 37 | s.GenericScript.env = env 38 | s.GenericScript.jobid = jobid 39 | s.GenericScript.timeout = timeout 40 | s.GenericScript.args = args 41 | return s 42 | } 43 | 44 | func (s NameScript) Run() (r model.ResCmd) { 45 | 46 | cmdstr, args := getCmdArgs(s.cmd) 47 | command := cmd.BuildCommand(cmdstr) 48 | command.Args = append(command.Args, args...) 49 | command.Args = append(command.Args, s.content) 50 | command.Args = append(command.Args, s.args...) 51 | command.Timeout = s.timeout 52 | command.User = s.user 53 | command.WorkingDir = s.path 54 | 55 | if s.input != "" { 56 | command.Stdin = strings.NewReader(s.input) 57 | } 58 | 59 | for key, val := range s.env { 60 | command.Env[key] = val 61 | } 62 | 63 | res, err := s.runner.RunCommand(s.jobid, command) 64 | return s.getResCmd(res, err) 65 | } 66 | -------------------------------------------------------------------------------- /pkg/agent/script/pack_script.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "context" 5 | "go-ops/internal/model" 6 | "go-ops/pkg/agent/action" 7 | "go-ops/pkg/agent/cmdrunner" 8 | "go-ops/pkg/agent/script/cmd" 9 | "path" 10 | "path/filepath" 11 | "strings" 12 | ) 13 | 14 | // 压缩包脚本,脚本放在一个压缩包内 15 | type PackScript struct { 16 | GenericScript 17 | cmd string 18 | input string 19 | fileMd5 string 20 | } 21 | 22 | func NewPackScript( 23 | runner cmdrunner.CmdRunner, 24 | jobid string, 25 | path string, 26 | cmd string, 27 | content string, 28 | env map[string]string, 29 | timeout int, 30 | input string, 31 | user string, 32 | args []string, 33 | filemd5 string, 34 | ) PackScript { 35 | 36 | if cmd == "" { 37 | cmd = Cmder 38 | } 39 | 40 | s := PackScript{cmd: cmd, input: input, fileMd5: filemd5} 41 | s.GenericScript.runner = runner 42 | s.GenericScript.path = path 43 | s.GenericScript.content = content 44 | s.GenericScript.env = env 45 | s.GenericScript.jobid = jobid 46 | s.GenericScript.timeout = timeout 47 | s.GenericScript.user = user 48 | s.GenericScript.args = args 49 | 50 | return s 51 | } 52 | 53 | func (s PackScript) Run() (r model.ResCmd) { 54 | 55 | if s.path == "" { 56 | s.path = ScriptPath 57 | } 58 | runpath := path.Join(s.path, s.jobid) 59 | err := s.ensureContainingDir(runpath) 60 | 61 | if err != nil { 62 | return s.getResCmd(nil, err) 63 | } 64 | 65 | filename := filepath.Join(runpath, filepath.Base(s.content)) 66 | 67 | ctx := context.Background() 68 | 69 | err = action.Download(ctx, filename, s.content) 70 | 71 | if err != nil { 72 | return s.getResCmd(nil, err) 73 | } 74 | 75 | err = action.CheckFileMd5(filename, s.fileMd5) 76 | if err != nil { 77 | return s.getResCmd(nil, err) 78 | } 79 | 80 | err = action.Untar(filename) 81 | if err != nil { 82 | return s.getResCmd(nil, err) 83 | } 84 | 85 | cmdstr, args := getCmdArgs(s.cmd) 86 | 87 | command := cmd.BuildCommand(cmdstr) 88 | 89 | command.Args = append(command.Args, args...) 90 | command.Args = append(command.Args, runpath) 91 | command.Args = append(command.Args, s.args...) 92 | command.Timeout = s.timeout 93 | command.User = s.user 94 | command.WorkingDir = s.path 95 | 96 | if s.input != "" { 97 | command.Stdin = strings.NewReader(s.input) 98 | } 99 | 100 | for key, val := range s.env { 101 | command.Env[key] = val 102 | } 103 | 104 | res, err := s.runner.RunCommand(s.jobid, command) 105 | return s.getResCmd(res, err) 106 | } 107 | -------------------------------------------------------------------------------- /pkg/agent/script/pathenv/pathenv.go: -------------------------------------------------------------------------------- 1 | package pathenv 2 | 3 | import "os" 4 | 5 | func Path() string { return os.Getenv("PATH") } 6 | -------------------------------------------------------------------------------- /pkg/agent/script/plugin.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "go-ops/internal/model" 7 | "time" 8 | ) 9 | 10 | type ScriptPlugin struct { 11 | GenericScript 12 | cmd string 13 | input string 14 | } 15 | 16 | func NewScriptPlugin( 17 | jobid string, 18 | path string, 19 | cmd string, 20 | content string, 21 | env map[string]string, 22 | timeout int, 23 | input string, 24 | user string, 25 | args []string, 26 | ) ScriptPlugin { 27 | 28 | if cmd == "" { 29 | cmd = Cmder 30 | } 31 | 32 | s := ScriptPlugin{cmd: cmd, input: input} 33 | s.GenericScript.path = path 34 | s.GenericScript.content = content 35 | s.GenericScript.env = env 36 | s.GenericScript.jobid = jobid 37 | s.GenericScript.timeout = timeout 38 | s.GenericScript.user = user 39 | s.GenericScript.args = args 40 | 41 | return s 42 | } 43 | 44 | func (s ScriptPlugin) Run() (r model.ResCmd) { 45 | 46 | opsAgentPlugin := new(AgentPlugin) 47 | 48 | err := json.Unmarshal([]byte(s.content), opsAgentPlugin) 49 | if err != nil { 50 | r.Err = err.Error() 51 | return 52 | } 53 | 54 | opsAgentPlugin.Args = s.args 55 | opsAgentPlugin.Cmd = s.cmd 56 | opsAgentPlugin.Timeout = time.Duration(s.timeout * int(time.Second)) 57 | 58 | res, err := opsAgentPlugin.Run(context.Background(), []byte(s.input)) 59 | 60 | if err != nil { 61 | r.Err = err.Error() 62 | return 63 | } 64 | 65 | r.Res = res 66 | 67 | return 68 | } 69 | -------------------------------------------------------------------------------- /pkg/agent/script/script_interface.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import "go-ops/internal/model" 4 | 5 | type Script interface { 6 | Path() string 7 | Run() model.ResCmd 8 | } 9 | 10 | //counterfeiter:generate . CancellableScript 11 | 12 | type CancellableScript interface { 13 | Script 14 | Cancel() error 15 | } 16 | -------------------------------------------------------------------------------- /pkg/agent/script/url_script.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "go-ops/internal/model" 5 | "go-ops/pkg/agent/cmdrunner" 6 | "go-ops/pkg/agent/script/cmd" 7 | "io" 8 | "net/http" 9 | "os" 10 | "path" 11 | "strings" 12 | ) 13 | 14 | type UrlScript struct { 15 | GenericScript 16 | cmd string 17 | input string 18 | } 19 | 20 | func NewUrlScript( 21 | runner cmdrunner.CmdRunner, 22 | jobid string, 23 | path string, 24 | cmd string, 25 | content string, 26 | env map[string]string, 27 | timeout int, 28 | user string, 29 | args []string, 30 | input string, 31 | ) UrlScript { 32 | 33 | if cmd == "" { 34 | cmd = Cmder 35 | } 36 | 37 | s := UrlScript{cmd: cmd, input: input} 38 | s.GenericScript.runner = runner 39 | s.GenericScript.path = path 40 | s.GenericScript.content = content 41 | s.GenericScript.env = env 42 | s.GenericScript.jobid = jobid 43 | s.GenericScript.timeout = timeout 44 | s.GenericScript.user = user 45 | s.GenericScript.args = args 46 | return s 47 | } 48 | 49 | func (s UrlScript) Run() (r model.ResCmd) { 50 | 51 | err := s.downloadFile() 52 | if err != nil { 53 | return s.getResCmd(nil, err) 54 | } 55 | cmdstr, args := getCmdArgs(s.cmd) 56 | command := cmd.BuildCommand(cmdstr) 57 | command.Args = append(command.Args, args...) 58 | 59 | filename := path.Base(s.content) 60 | 61 | command.Args = append(command.Args, filename) 62 | command.Args = append(command.Args, s.args...) 63 | command.Timeout = s.timeout 64 | command.User = s.user 65 | command.WorkingDir = s.path 66 | 67 | for key, val := range s.env { 68 | command.Env[key] = val 69 | } 70 | 71 | if s.input != "" { 72 | command.Stdin = strings.NewReader(s.input) 73 | } 74 | 75 | res, err := s.runner.RunCommand(s.jobid, command) 76 | return s.getResCmd(res, err) 77 | } 78 | 79 | func (s UrlScript) downloadFile() (err error) { 80 | savePath := s.path 81 | if savePath == ScriptPath { 82 | savePath = path.Join(s.path, s.jobid) 83 | } 84 | 85 | filename := path.Base(s.content) 86 | 87 | savePath = path.Join(savePath, filename) 88 | 89 | err = s.ensureContainingDir(savePath) 90 | if err != nil { 91 | return 92 | } 93 | 94 | f, err := os.OpenFile(savePath, fileOpenFlag, fileOpenPerm) 95 | if err != nil { 96 | return 97 | } 98 | defer f.Close() 99 | 100 | res, err := http.Get(s.content) 101 | if err != nil { 102 | return 103 | } 104 | defer res.Body.Close() 105 | 106 | _, err = io.Copy(f, res.Body) 107 | return 108 | } 109 | -------------------------------------------------------------------------------- /pkg/agent/task/async_task_service.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "github.com/panjf2000/ants/v2" 5 | ) 6 | 7 | type asyncTaskService struct { 8 | currentTasks map[string]Task 9 | taskChan chan Task 10 | taskSem chan func() 11 | taskPool *ants.PoolWithFunc 12 | } 13 | 14 | func NewAsyncTaskService() (service Service) { 15 | s := asyncTaskService{ 16 | currentTasks: make(map[string]Task), 17 | taskChan: make(chan Task), 18 | taskSem: make(chan func()), 19 | } 20 | 21 | p, _ := ants.NewPoolWithFunc(100, s.execTask) 22 | 23 | s.taskPool = p 24 | go s.processTasks() 25 | go s.processSemFuncs() 26 | 27 | return s 28 | } 29 | 30 | func (service asyncTaskService) CreateTask( 31 | id string, 32 | req interface{}, 33 | taskFunc Func, 34 | cancelFunc CancelFunc, 35 | endFunc EndFunc, 36 | ) Task { 37 | return Task{ 38 | ID: id, 39 | Req: req, 40 | State: StateRunning, 41 | Func: taskFunc, 42 | CancelFunc: cancelFunc, 43 | EndFunc: endFunc, 44 | } 45 | } 46 | 47 | func (service asyncTaskService) StartTask(task Task) { 48 | taskChan := make(chan Task) 49 | 50 | service.taskSem <- func() { 51 | service.currentTasks[task.ID] = task 52 | taskChan <- task 53 | } 54 | 55 | recordedTask := <-taskChan 56 | service.taskChan <- recordedTask 57 | } 58 | 59 | func (service asyncTaskService) FindTaskWithID(id string) (Task, bool) { 60 | taskChan := make(chan Task) 61 | foundChan := make(chan bool) 62 | 63 | service.taskSem <- func() { 64 | task, found := service.currentTasks[id] 65 | taskChan <- task 66 | foundChan <- found 67 | } 68 | 69 | return <-taskChan, <-foundChan 70 | } 71 | 72 | func (service asyncTaskService) processSemFuncs() { 73 | 74 | for { 75 | do := <-service.taskSem 76 | do() 77 | } 78 | } 79 | 80 | func (service asyncTaskService) processTasks() { 81 | 82 | for { 83 | task := <-service.taskChan 84 | service.taskPool.Invoke(task) 85 | 86 | } 87 | } 88 | 89 | func (service asyncTaskService) execTask(val interface{}) { 90 | task := val.(Task) 91 | value, err := task.Func() 92 | if err != nil { 93 | task.Error = err 94 | task.State = StateFailed 95 | } else { 96 | task.Value = value 97 | task.State = StateDone 98 | } 99 | 100 | if task.EndFunc != nil { 101 | task.EndFunc(task) 102 | } 103 | 104 | task.Func = nil 105 | task.CancelFunc = nil 106 | task.EndFunc = nil 107 | 108 | service.taskSem <- func() { 109 | service.currentTasks[task.ID] = task 110 | } 111 | 112 | } 113 | 114 | func (service asyncTaskService) Stop() { 115 | for _, item := range service.currentTasks { 116 | if item.State == StateRunning { 117 | item.Cancel() 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /pkg/agent/task/service_interface.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | type Service interface { 4 | CreateTask(string, interface{}, Func, CancelFunc, EndFunc) Task 5 | StartTask(Task) 6 | FindTaskWithID(string) (Task, bool) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/agent/task/task.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | type Func func() (value interface{}, err error) 4 | 5 | type CancelFunc func(task Task) error 6 | 7 | type EndFunc func(task Task) 8 | 9 | type State string 10 | 11 | const ( 12 | StateRunning State = "running" 13 | StateDone State = "done" 14 | StateFailed State = "failed" 15 | ) 16 | 17 | type Task struct { 18 | ID string 19 | Req interface{} // 请求参数 20 | State State 21 | Value interface{} 22 | Error error 23 | 24 | Func Func 25 | CancelFunc CancelFunc 26 | EndFunc EndFunc 27 | } 28 | 29 | func (t Task) Cancel() error { 30 | if t.CancelFunc != nil { 31 | return t.CancelFunc(t) 32 | } 33 | return nil 34 | } 35 | 36 | type StateValue struct { 37 | AgentTaskID string `json:"agent_task_id"` 38 | State State `json:"state"` 39 | } 40 | -------------------------------------------------------------------------------- /pkg/agent/task/task_manager_interface.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | type Info struct { 4 | TaskID string 5 | Method string 6 | Payload []byte 7 | } 8 | 9 | type ManagerProvider interface { 10 | NewManager(string) Manager 11 | } 12 | 13 | type Manager interface { 14 | GetInfos() ([]Info, error) 15 | AddInfo(taskInfo Info) error 16 | RemoveInfo(taskID string) error 17 | } 18 | -------------------------------------------------------------------------------- /pkg/agent/test/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "go-ops/internal/model" 7 | "go-ops/pkg/agent" 8 | "go-ops/pkg/agent/script" 9 | "go-ops/pkg/agent/task" 10 | ) 11 | 12 | func main() { 13 | 14 | s := model.Script{ 15 | Content: "ping baidu.com", 16 | } 17 | s1 := model.ScriptJob{ 18 | Jobid: "1111", 19 | Script: s, 20 | } 21 | 22 | ctx, cancel := context.WithCancel(context.Background()) 23 | startFunc := func() (r interface{}, err error) { 24 | 25 | res := script.NewJobScriptProvider(ctx, s1).Run() 26 | r = &model.ResponseResCmd{ 27 | Jobid: s1.Jobid, 28 | ResCmd: res, 29 | } 30 | 31 | return 32 | } 33 | 34 | endFunc := func(t task.Task) { 35 | 36 | fmt.Println("end -> ") 37 | 38 | } 39 | 40 | c := func(t task.Task) error { 41 | fmt.Println("取消") 42 | cancel() 43 | return nil 44 | } 45 | 46 | ospAgent := agent.NewOspAgent("./") 47 | t := ospAgent.CreateTask(s1.Jobid, s1, startFunc, c, endFunc) 48 | ospAgent.StartTask(t) 49 | // ospAgent.StartTask(t) 50 | 51 | select {} 52 | 53 | } 54 | -------------------------------------------------------------------------------- /pkg/agent/test/test2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | ) 8 | 9 | func main() { 10 | 11 | res, err := exec.Command("echo", "$HOME").CombinedOutput() 12 | if err != nil { 13 | return 14 | } 15 | 16 | s := os.ExpandEnv("echo hello") 17 | fmt.Println("s:", s) 18 | 19 | fmt.Println(string(res)) 20 | } 21 | -------------------------------------------------------------------------------- /pkg/agent/test/test3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "go-ops/internal/model" 7 | "go-ops/pkg/agent/script" 8 | "os" 9 | "os/signal" 10 | "syscall" 11 | ) 12 | 13 | func main() { 14 | s := model.Script{ 15 | Content: "ping baidu.com", 16 | } 17 | s1 := model.ScriptJob{ 18 | Jobid: "1111", 19 | Script: s, 20 | } 21 | fmt.Println("tttt->") 22 | 23 | ctx, cancel := context.WithCancel(context.Background()) 24 | go handlesig(func() { 25 | cancel() 26 | }) 27 | res := script.NewJobScriptProvider(ctx, s1).Run() 28 | 29 | fmt.Println(res) 30 | 31 | } 32 | 33 | func handlesig(f func()) { 34 | c := make(chan os.Signal, 1) 35 | signal.Notify( 36 | c, 37 | syscall.SIGINT, 38 | syscall.SIGTERM, 39 | syscall.SIGKILL, 40 | syscall.SIGQUIT, 41 | ) 42 | sig := <-c 43 | fmt.Println("sig:", sig) 44 | f() 45 | 46 | } 47 | -------------------------------------------------------------------------------- /pkg/api/v1/agent_info.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/gogf/gf/v2/frame/g" 5 | ) 6 | 7 | type AddAgentReq struct { 8 | g.Meta `path:"/peer/agent/add" tags:"Agent管理" method:"post" summary:"节点添加agent"` 9 | List []*AgentInfo `json:"list"` 10 | } 11 | 12 | type AgentInfo struct { 13 | Peerid string `json:"peerid" dc:"节点id, 空表示默认版本,所有节点将使用这个版本" ` // 节点id 14 | Name string `json:"name" dc:"agent 名称" ` // agent名称 15 | Version string `json:"version" dc:"agent 版本"` 16 | ExpectedStatus string `json:"expectedStatus" dc:"期望状态 running,stopped,deleted" ` // 期望状态 17 | DownloadUrl string `json:"downloadUrl" dc:"下载地址"` // 下载地址 18 | Status string `json:"status" dc:"agent 当前状态" ` // 当前agent状态 19 | IsDefault int `json:"isDefault" dc:"是否默认安装 0-否 1-是" ` // 20 | Timeout int `json:"timeout" dc:"agent 启动超时时间" ` // 启动超时时间 21 | } 22 | 23 | type AgentInfoRes struct { 24 | List []*AgentInfo `json:"list"` 25 | } 26 | 27 | type UpdateAgentReq struct { 28 | g.Meta `path:"/peer/agent/update" tags:"Agent管理" method:"post" summary:"节点更新agent"` 29 | List []*AgentInfo `json:"list"` 30 | } 31 | 32 | type QueryAgentStatusReq struct { 33 | g.Meta `path:"/peer/agent/status" tags:"Agent管理" method:"post" summary:"查询agent状态"` 34 | List []*QueryAgentStatus `json:"list"` 35 | } 36 | 37 | type QueryAgentStatus struct { 38 | Peerid string `json:"peerid" dc:"节点id"` 39 | Agents []string `json:"agents" dc:"需要查询的agent名称列表"` 40 | } 41 | 42 | type PeerAgentStatus struct { 43 | Peerid string `json:"peerid" dc:"节点id"` 44 | Agents []*AgentInfo 45 | } 46 | 47 | type QueryAgentStatusRes struct { 48 | List []*PeerAgentStatus 49 | } 50 | -------------------------------------------------------------------------------- /pkg/api/v1/app.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "go-ops/internal/model/entity" 5 | 6 | "github.com/gogf/gf/v2/frame/g" 7 | ) 8 | 9 | type AddAppReq struct { 10 | g.Meta `path:"/v1/m/app/create" tags:"App管理" method:"post" summary:"创建一个app"` 11 | Name string `json:"name" dc:"应用名"` // 应用名 12 | Owner string `json:"owner" dc:"拥有者"` // 拥有者 13 | } 14 | 15 | type AddAppRes struct { 16 | Appid string `json:"appid" dc:"appid" ` // 17 | ApiKey string `json:"apiKey" ` // 18 | SecKey string `json:"secKey" ` // 19 | Owner string `json:"owner" dc:"拥有者" ` // 20 | Name string `json:"name" dc:"应用名" ` // 应用名 21 | Status int `json:"status" dc:"状态 1启用 0 禁用" ` // 1启用 0 禁用 22 | OwnerUid string `json:"ownerUid" dc:"拥有者uid" ` // 拥有者uid 23 | } 24 | 25 | type UpdateAppReq struct { 26 | g.Meta `path:"/v1/m/app/update" tags:"App管理" method:"post" summary:"更新一个app"` 27 | Appid string `json:"appid" dc:"appid" ` // 28 | Name string `json:"name" dc:"应用名"` // 应用名 29 | Owner string `json:"owner" dc:"拥有者"` // 拥有者 30 | Status int `json:"status" dc:"状态 1启用 0 禁用" ` // 1启用 0 禁用 31 | } 32 | 33 | type QueryAppReq struct { 34 | g.Meta `path:"/v1/m/app/query" tags:"App管理" method:"post" summary:"查询app"` 35 | Name string `json:"name" dc:"应用名"` // 应用名 36 | Owner string `json:"owner" dc:"拥有者"` // 拥有者 37 | PageReq 38 | } 39 | 40 | type QuerySingleAppReq struct { 41 | g.Meta `path:"/v1/m/app/single_query" tags:"App管理" method:"post" summary:"通过id查询app"` 42 | AppId string `json:"appid" dc:"appid"` // 应用名 43 | } 44 | 45 | type QueryAppRes struct { 46 | Page 47 | List []*entity.App `json:"list"` 48 | } 49 | 50 | type DeleteAppReq struct { 51 | g.Meta `path:"/v1/m/app/delete" tags:"App管理" method:"post" summary:"删除app"` 52 | Appids []string `json:"appids" dc:"app id 列表"` 53 | } 54 | -------------------------------------------------------------------------------- /pkg/api/v1/base.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | type DeleteRes string 4 | 5 | type Page struct { 6 | Total int `json:"total" dc:"总数"` 7 | PageNum int `json:"pageNum" dc:"第几页"` 8 | PageSize int `json:"pageSize" dc:"每页的数量"` 9 | PageTotal int `json:"pageTotal" dc:"总共多少页"` 10 | } 11 | 12 | type PageReq struct { 13 | PageNum int `json:"pageNum" dc:"第几页" d:"1" v:"min:0#分页号码错误"` 14 | PageSize int `json:"pageSize" dc:"每页的数量" d:"10" v:"max:50#分页数量最大50条"` 15 | } 16 | 17 | type KVString struct { 18 | Key string `json:"key"` 19 | Value string `json:"value"` 20 | Desc string `json:"desc"` 21 | } 22 | -------------------------------------------------------------------------------- /pkg/api/v1/check.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import "github.com/gogf/gf/v2/frame/g" 4 | 5 | type AddCheckItemReq struct { 6 | g.Meta `path:"/check/item/add" tags:"巡检管理" method:"post" summary:"添加巡检项"` 7 | Name string `json:"name" dc:"检查项名称" ` // 检查项名称 8 | Desc string `json:"desc" dc:"检查项描述" ` // 检查项描述 9 | Type string `json:"type" dc:"类型" ` // 10 | Content string `json:"content" dc:"内容" ` // 检查项内容 11 | WaitTime int `json:"waitTime" dc:"脚本超时时间"` 12 | Cmd string `json:"cmd" dc:"脚本解释器"` 13 | Weight float64 `json:"weight" 权重` 14 | } 15 | 16 | type CheckItemRes struct { 17 | CheckItemId string `json:"checkItemId" dc:"检查项id"` 18 | Name string `json:"name" dc:"检查项名称" ` // 检查项名称 19 | Desc string `json:"desc" dc:"检查项描述" ` // 检查项描述 20 | Type string `json:"type" dc:"类型" ` // 21 | Content string `json:"content" dc:"内容" ` // 检查项内容 22 | WaitTime int `json:"waitTime" dc:"脚本超时时间"` 23 | Cmd string `json:"cmd" dc:"脚本解释器"` 24 | Weight float64 `json:"weight" 权重` 25 | } 26 | 27 | type UpdateCheckItemReq struct { 28 | g.Meta `path:"/check/item/update" tags:"巡检管理" method:"post" summary:"更新检查项"` 29 | CheckItemRes 30 | } 31 | 32 | type QueryCheckItemReq struct { 33 | g.Meta `path:"/check/item/query" tags:"巡检管理" method:"post" summary:"查询检查项"` 34 | CheckItemId string `json:"checkItemId" dc:"检查项id"` 35 | Name string `json:"name" dc:"检查项名称" ` // 检查项名称 36 | Type string `json:"type" dc:"类型" ` // 37 | PageReq 38 | } 39 | 40 | type QueryCheckItemRes struct { 41 | Page 42 | List []*CheckItemRes `json:"list"` 43 | } 44 | 45 | type DeleteCheckItemReq struct { 46 | g.Meta `path:"/check/item/delete" tags:"巡检管理" method:"post" summary:"删除检查项"` 47 | CheckItemIds []string `json:"checkItemIds" dc:"检查项id列表"` 48 | } 49 | 50 | type CheckTplItemInfo struct { 51 | ItemId string `json"itemId" dc:"巡检项id"` 52 | Weight float64 `json:"weight" dc:"权重"` 53 | } 54 | 55 | type CheckTplItem struct { 56 | Tid string `json:"tid"` 57 | Name string `json:"name" dc:"检查项名称" ` // 检查项名称 58 | Desc string `json:"desc" dc:"检查项描述" ` // 检查项描述 59 | Type string `json:"type" dc:"类型" ` // 60 | Items []*CheckTplItemInfo `json:"items" dc:"items"` // 61 | } 62 | 63 | type CheckTplItemRes *CheckTplItem 64 | 65 | type AddCheckTplReq struct { 66 | g.Meta `path:"/check/tpl/create" tags:"巡检管理" method:"post" summary:"添加巡检模版"` 67 | CheckTplItem 68 | } 69 | 70 | type UpdateCheckTplReq struct { 71 | g.Meta `path:"/check/tpl/update" tags:"巡检管理" method:"post" summary:"更新巡检模版"` 72 | CheckTplItem 73 | } 74 | 75 | type DeleteCheckTplReq struct { 76 | g.Meta `path:"/check/tpl/delete" tags:"巡检管理" method:"post" summary:"删除巡检模版"` 77 | Tids []string `json:"tids"` 78 | } 79 | 80 | type QueryCheckTplReq struct { 81 | g.Meta `path:"/check/tpl/query" tags:"巡检管理" method:"post" summary:"查询巡检模版"` 82 | Tid string `json:"tid"` 83 | Name string `json:"name" dc:"检查项名称" ` // 检查项名称 84 | PageReq 85 | } 86 | -------------------------------------------------------------------------------- /pkg/api/v1/download_file.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "go-ops/internal/model" 5 | 6 | "github.com/gogf/gf/v2/frame/g" 7 | ) 8 | 9 | type DownloadFileReq struct { 10 | g.Meta `path:"/peer/downloadfile" tags:"文件分发" method:"post" summary:"创建文件分发任务"` 11 | Name string `json:"name" dc:"任务名称"` 12 | Creater string `json:"creater" dc:"创建人"` 13 | DownloadFileInfo 14 | } 15 | 16 | type DownloadFileInfo struct { 17 | Peers []string `json:"peers" dc:"节点列表"` 18 | Files []*model.DownloadFileInfo `json:"files" dc:""` 19 | } 20 | 21 | type DownloadfileRes struct { 22 | Taskid string `json:"taskid" dc:"任务id"` 23 | Status string `json:"status" dc:"状态(doing, failed, done)"` 24 | List []*DownloadfileItem `json:"list" dc:"任务列表详情"` 25 | } 26 | 27 | type DownloadfileItem struct { 28 | Status string `json:"status" dc:"状态(doing, failed, done)` 29 | model.DownloadFileJobRes 30 | } 31 | 32 | type DownloadFileDetailsReq struct { 33 | g.Meta `path:"/peer/downloadfile/details" tags:"文件分发" method:"post" summary:"文件分发任务详情"` 34 | Taskid string `json:"taskid"` 35 | } 36 | -------------------------------------------------------------------------------- /pkg/api/v1/fileinfo.go: -------------------------------------------------------------------------------- 1 | package v1 2 | -------------------------------------------------------------------------------- /pkg/api/v1/plugin.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "go-ops/internal/model/entity" 5 | 6 | "github.com/gogf/gf/v2/frame/g" 7 | ) 8 | 9 | type AddPluginReq struct { 10 | g.Meta `path:"/v1/m/plugin/create" tags:"插件" method:"post" summary:"添加插件"` 11 | Name string `json:"name" dc:"插件名" ` // 插件名 12 | PackageName string `json:"packageName" dc:"包名"` // 包名 13 | Os string `json:"os" dc:"操作系统" ` // 操作系统 14 | Arch string `json:"arch" dc:"架构" ` // 架构 15 | Md5 string `json:"md5" dc:"包md5名称" ` // 包md5名称 16 | Creater string `json:"creater" dc:"创建人"` 17 | } 18 | 19 | type PluginItemRes struct { 20 | Uuid string `json:"uuid" dc:"插件uuid"` 21 | Name string `json:"name" dc:"插件名" ` // 插件名 22 | PackageName string `json:"packageName" dc:"包名"` // 包名 23 | Os string `json:"os" dc:"操作系统" ` // 操作系统 24 | Arch string `json:"arch" dc:"架构" ` // 架构 25 | Md5 string `json:"md5" dc:"包md5名称" ` // 包md5名称 26 | Creater string `json:"creater" dc:"创建人"` 27 | Updater string `json:"updater" dc:"更新人"` 28 | Created string `json:"created" dc:"创建时间"` 29 | Updated string `json:"updated" dc:"更新时间"` 30 | } 31 | 32 | type UpdatePluginReq struct { 33 | g.Meta `path:"/v1/m/plugin/update" tags:"插件" method:"post" summary:"更新插件"` 34 | PluginItemRes 35 | } 36 | 37 | type DeletePluginReq struct { 38 | g.Meta `path:"/v1/m/plugin/delete" tags:"插件" method:"post" summary:"删除插件"` 39 | Uuids []string `json:"uuids" dc:"插件uuid列表"` 40 | } 41 | 42 | type QueryPluginReq struct { 43 | g.Meta `path:"/v1/m/plugin/query" tags:"插件" method:"post" summary:"查询插件"` 44 | PageReq 45 | PluginItemRes 46 | } 47 | 48 | type QueryPluginRes struct { 49 | Page 50 | List []*entity.Plugin `json:"list"` 51 | } 52 | -------------------------------------------------------------------------------- /pkg/api/v1/pmanager.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "go-ops/internal/model" 5 | 6 | "github.com/gogf/gf/v2/frame/g" 7 | "github.com/luxingwen/pnet/protos" 8 | "github.com/luxingwen/pnet/stat" 9 | ) 10 | 11 | type NodeReq struct { 12 | g.Meta `path:"/peer/nodes" tags:"节点管理" method:"post" summary:"获取节点连接信息"` 13 | NodeId string `json:"nodeid" dc:"节点id,空表示当前节点"` 14 | } 15 | 16 | type NodeRes struct { 17 | Nodes []*protos.Node `json:"" dc:"节点列表"` 18 | } 19 | 20 | type NodeConnectReq struct { 21 | g.Meta `path:"/peer/node/connect" tags:"节点管理" method:"post" summary:"连接节点"` 22 | NodeId string `json:"nodeid" dc:"节点id"` 23 | RemoteAddr string `json:"remoteAddr" dc:"远程节点连接地址"` 24 | } 25 | 26 | type NodeOpRes struct { 27 | Msg string `json:"msg"` 28 | } 29 | 30 | type NodeStopReq struct { 31 | g.Meta `path:"/peer/node/stop" tags:"节点管理" method:"post" summary:"停止节点连接"` 32 | NodeId string `json:"nodeid"` 33 | RemoteId string `json:"remoteId"` 34 | } 35 | 36 | type NodeStatReq struct { 37 | g.Meta `path:"/peer/node/stat" tags:"节点管理" method:"post" summary:"获取节点状态"` 38 | NodeId string `json:"nodeid"` 39 | } 40 | 41 | type NodeStatRes struct { 42 | *stat.NodeStat 43 | } 44 | 45 | type NodeFileListReq struct { 46 | g.Meta `path:"/peer/node/files" tags:"节点管理" method:"post" summary:"获取节点文件夹信息"` 47 | NodeId string `json:"nodeid"` 48 | Path string `json:"path" dc:"路径"` 49 | } 50 | 51 | type NodeFileListRes struct { 52 | Files []*model.FileInfo `json:"files"` 53 | } 54 | 55 | type NodeFileCreateDirReq struct { 56 | g.Meta `path:"/peer/node/files/createDir" tags:"节点管理" method:"post" summary:"创建节点文件夹"` 57 | NodeId string `json:"nodeid"` 58 | Path string `json:"path" dc:"文件夹路径"` 59 | } 60 | 61 | type NodeFileDeleteReq struct { 62 | g.Meta `path:"/peer/node/files/delete" tags:"节点管理" method:"post" summary:"删除节点文件"` 63 | NodeId string `json:"nodeid"` 64 | Path string `json:"path" dc:"文件夹(文件)路径"` 65 | } 66 | 67 | type NodeFileMoveReq struct { 68 | g.Meta `path:"/peer/node/files/move" tags:"节点管理" method:"post" summary:"移动节点文件"` 69 | NodeId string `json:"nodeid"` 70 | Src string `json:"src" dc:"源文件夹(文件)路径"` 71 | Dst string `json:"dst" dc:"目标文件夹(文件)路径"` 72 | } 73 | -------------------------------------------------------------------------------- /pkg/api/v1/script.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "go-ops/internal/model/entity" 5 | 6 | "github.com/gogf/gf/v2/frame/g" 7 | ) 8 | 9 | type AddScriptReq struct { 10 | g.Meta `path:"/v1/m/script/add" tags:"脚本库管理" method:"post" summary:"创建一个脚本"` 11 | Name string `json:"name" dc:"脚本名称" ` // 命令名称 12 | Content string `json:"content" dc:"脚本内容" ` // 脚本内容 13 | Args []*KVString `json:"args" dc:"参数信息" ` // 参数信息 14 | Desc string `json:"desc" dc:"描述信息" ` // 描述信息 15 | Type string `json:"type" dc:"脚本类型shell或者powershell" ` // 脚本类型shell或者powershell 16 | Creater string `json:"creater" dc:"创建人"` 17 | WaitTime int `json:"waitTime" dc:"脚本超时时间"` 18 | Cmd string `json:"cmd" dc:"脚本解释器"` 19 | Ext string `json:"ext" dc:"脚本文件扩展名"` 20 | } 21 | 22 | type ScriptQueryReq struct { 23 | g.Meta `path:"/v1/m/script/query" tags:"脚本库管理" method:"post" summary:"查询脚本库信息"` 24 | Name string `json:"name" dc:"脚本名称" ` 25 | Type string `json:"type" dc:"脚本类型shell或者powershell"` 26 | ScriptId string `json:"scriptId" dc:"脚本id"` 27 | PageReq 28 | } 29 | 30 | type ScriptInfoRes struct { 31 | Page 32 | List []*entity.Script `json:"list"` 33 | } 34 | 35 | type UpdateScriptReq struct { 36 | g.Meta `path:"/v1/m/script/update" tags:"脚本库管理" method:"post" summary:"更新脚本信息"` 37 | ScriptId string `json:"scriptId" dc:"脚本id"` 38 | Name string `json:"name" dc:"脚本名称" ` // 命令名称 39 | Content string `json:"content" dc:"脚本内容" ` // 脚本内容 40 | Args []*KVString `json:"args" dc:"参数信息" ` // 参数信息 41 | Desc string `json:"desc" dc:"描述信息" ` // 描述信息 42 | Type string `json:"type" dc:"脚本类型shell或者powershell" ` // 脚本类型shell或者powershell 43 | Updater string `json:"updater" dc:"更新人"` 44 | WaitTime int `json:"waitTime" dc:"脚本超时时间"` 45 | Cmd string `json:"cmd" dc:"脚本解释器"` 46 | Ext string `json:"ext" dc:"脚本文件扩展名"` 47 | } 48 | 49 | type ScriptItemRes struct { 50 | ScriptId string `json:"scriptId" dc:"脚本id"` 51 | Name string `json:"name" dc:"脚本名称" ` // 命令名称 52 | Content string `json:"content" dc:"脚本内容" ` // 脚本内容 53 | Args []*KVString `json:"args" dc:"参数信息" ` // 参数信息 54 | Desc string `json:"desc" dc:"描述信息" ` // 描述信息 55 | Type string `json:"type" dc:"脚本类型shell或者powershell" ` // 脚本类型shell或者powershell 56 | Creater string `json:"creater" dc:"创建人"` 57 | Updater string `json:"updater" dc:"更新人"` 58 | WaitTime int `json:"waitTime" dc:"脚本超时时间"` 59 | Cmd string `json:"cmd" dc:"脚本解释器"` 60 | Ext string `json:"ext" dc:"脚本文件扩展名"` 61 | } 62 | 63 | type DeleteScriptReq struct { 64 | g.Meta `path:"/v1/m/script/delete" tags:"脚本库管理" method:"post" summary:"删除脚本信息"` 65 | ScriptIds []string `json:"scriptIds" dc:"脚本id 列表"` 66 | } 67 | 68 | type DeleteScriptRes string 69 | -------------------------------------------------------------------------------- /pkg/api/v1/script_task.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "go-ops/internal/model" 5 | 6 | "github.com/gogf/gf/v2/frame/g" 7 | ) 8 | 9 | type ScriptTaskReq struct { 10 | g.Meta `path:"/script/async" tags:"脚本任务" method:"post" summary:"脚本异步执行"` 11 | ScriptTask 12 | } 13 | 14 | type ScriptTask struct { 15 | Name string `json:"name" dc:"脚本任务名"` 16 | Creater string `json:"creater" dc:"创建者"` 17 | Peers []string `json:"peers" dc:"节点id列表"` 18 | Content model.Script `json:"content" dc:"脚本内容信息"` 19 | } 20 | 21 | type ScriptTaskRes struct { 22 | TaskId string `json:"taskid" dc:"任务id"` 23 | } 24 | 25 | type ScriptRes struct { 26 | List []*model.ResponseResCmd `json:"list" dc:"脚本任务详情列表"` 27 | } 28 | 29 | type ScriptTaskSyncReq struct { 30 | g.Meta `path:"/script/sync" tags:"脚本任务" method:"post" summary:"脚本同步执行"` 31 | ScriptTask 32 | } 33 | 34 | type ScriptTaskCancelReq struct { 35 | g.Meta `path:"/script/cancel" tags:"脚本任务" method:"post" summary:"取消脚本运行"` 36 | Tasks []ScriptTaskCancel `json:"tasks"` 37 | } 38 | 39 | type ScriptTaskCancel struct { 40 | PeerId string `json:"peerid" dc:"节点id"` 41 | Jobid string `json:"jobid" dc:"任务id"` 42 | Msg string `json:"msg"` 43 | } 44 | 45 | type ScriptTaskCancelRes struct { 46 | List []*ScriptTaskCancel `json:"list"` 47 | } 48 | 49 | type PeerScriptTaskInfoReq struct { 50 | g.Meta `path:"/script/peer/taskinfo" tags:"脚本任务" method:"post" summary:"远程节点上的脚本任务信息"` 51 | PeerId string `json:"peerid" dc:"节点id"` 52 | TaskId string `json:"taskid" dc:"任务id"` 53 | } 54 | 55 | type ScriptTaskInfoRes struct { 56 | PeerId string `json:"peerid"` 57 | *model.TaskInfo 58 | } 59 | 60 | type ScriptTaskExecItem struct { 61 | *model.ResponseResCmd 62 | Status string `json:"status"` 63 | } 64 | 65 | type ScriptTaskExecRes struct { 66 | TaskId string `json:"taskid" dc:"任务id"` 67 | Status string `json:"status"` 68 | List []*ScriptTaskExecItem `json:"list"` 69 | } 70 | 71 | type ScriptTaskInfoReq struct { 72 | g.Meta `path:"/script/taskinfo" tags:"脚本任务" method:"post" summary:"脚本任务信息"` 73 | TaskId string `json:"taskid"` 74 | } 75 | -------------------------------------------------------------------------------- /pkg/api/v1/user.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/gogf/gf/v2/frame/g" 7 | ) 8 | 9 | type AuthLoginReq struct { 10 | g.Meta `path:"/user/login" method:"post" tags:"用户" summary:"登录"` 11 | Username string `json:"username" dc:"username"` 12 | Passwd string `json:"passwd"` 13 | } 14 | 15 | type AuthLoginRes struct { 16 | Token string `json:"token"` 17 | Expire time.Time `json:"expire"` 18 | } 19 | 20 | type AuthRefreshTokenReq struct { 21 | g.Meta `path:"/user/refresh_token" method:"post" tags:"用户" summary:"token续期"` 22 | } 23 | 24 | type AuthRefreshTokenRes struct { 25 | Token string `json:"token"` 26 | Expire time.Time `json:"expire"` 27 | } 28 | 29 | type AuthLogoutReq struct { 30 | g.Meta `path:"/user/logout" method:"post" tags:"用户" summary:"登出"` 31 | } 32 | 33 | type AuthLogoutRes struct { 34 | } 35 | 36 | type CurrentUserInfoReq struct { 37 | g.Meta `path:"/user/info" method:"get" tags:"用户" summary:"用户信息"` 38 | } 39 | 40 | type UserInfoRes struct { 41 | Uid string `json:"uid" dc:"uid"` 42 | Username string `json:"username" dc:"username"` 43 | Email string `json:"email"` 44 | Phone string `json:"phone"` 45 | Avatar string `json:"avatar"` 46 | } 47 | -------------------------------------------------------------------------------- /pkg/api/v1/vm.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "go-ops/internal/model/entity" 5 | 6 | "github.com/gogf/gf/v2/frame/g" 7 | ) 8 | 9 | type AddVmReq struct { 10 | g.Meta `path:"/v1/m/vm/add" tags:"主机节点" method:"post" summary:"添加主机信息"` 11 | Name string `json:"name"` 12 | Hostname string `json:"hostname" dc:"主机hostname"` 13 | PublicIp string `json:"publicIp"` 14 | Uuid string `json:"uuid"` 15 | Os string `json:"os"` 16 | Creater string `json:"creater"` 17 | } 18 | 19 | type VmItemRes struct { 20 | PeerId string `json:"peerId"` 21 | Name string `json:"name"` 22 | Hostname string `json:"hostname" dc:"主机hostname"` 23 | PublicIp string `json:"publicIp"` 24 | Uuid string `json:"uuid"` 25 | Os string `json:"os"` 26 | Creater string `json:"creater"` 27 | Updater string `json:"updater"` 28 | } 29 | 30 | type UpdateVmReq struct { 31 | g.Meta `path:"/v1/m/vm/update" tags:"主机节点" method:"post" summary:"更新主机信息"` 32 | Name string `json:"name"` 33 | Uuid string `json:"uuid"` 34 | Os string `json:"os"` 35 | Updater string `json:"updater"` 36 | } 37 | 38 | type DeleteVmReq struct { 39 | g.Meta `path:"/v1/m/vm/delete" tags:"主机节点" method:"post" summary:"删除主机信息"` 40 | Uuids string `json:"uuids"` 41 | } 42 | 43 | type QueryVmReq struct { 44 | g.Meta `path:"/v1/m/vm/query" tags:"主机节点" method:"post" summary:"查询主机节点"` 45 | Name string `json:"name"` 46 | Uuid string `json:"uuid"` 47 | Hostname string `json:"hostname"` 48 | PeerId string `json:"peerId"` 49 | PageReq 50 | } 51 | 52 | type QueryVmRes struct { 53 | Page 54 | List []*entity.Vm `json:"list"` 55 | } 56 | -------------------------------------------------------------------------------- /pkg/consistenthash/consistenhash.go: -------------------------------------------------------------------------------- 1 | package consistenthash 2 | 3 | /* 4 | Copyright 2013 Google Inc. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | // Package consistenthash provides an implementation of a ring hash. 20 | 21 | import ( 22 | "hash/crc32" 23 | "sort" 24 | "strconv" 25 | ) 26 | 27 | type Hash func(data []byte) uint32 28 | 29 | type Map struct { 30 | hash Hash 31 | replicas int 32 | keys []int // Sorted 33 | hashMap map[int]string 34 | } 35 | 36 | func New(replicas int, fn Hash) *Map { 37 | m := &Map{ 38 | replicas: replicas, 39 | hash: fn, 40 | hashMap: make(map[int]string), 41 | } 42 | if m.hash == nil { 43 | m.hash = crc32.ChecksumIEEE 44 | } 45 | return m 46 | } 47 | 48 | // Returns true if there are no items available. 49 | func (m *Map) IsEmpty() bool { 50 | return len(m.keys) == 0 51 | } 52 | 53 | // Adds some keys to the hash. 54 | func (m *Map) Add(keys ...string) { 55 | for _, key := range keys { 56 | for i := 0; i < m.replicas; i++ { 57 | hash := int(m.hash([]byte(strconv.Itoa(i) + key))) 58 | if m.hashMap[hash] == "" { 59 | m.keys = append(m.keys, hash) 60 | m.hashMap[hash] = key 61 | } 62 | } 63 | } 64 | sort.Ints(m.keys) 65 | } 66 | 67 | // Gets the closest item in the hash to the provided key. 68 | func (m *Map) Get(key string) string { 69 | if m.IsEmpty() { 70 | return "" 71 | } 72 | 73 | hash := int(m.hash([]byte(key))) 74 | 75 | // Binary search for appropriate replica. 76 | idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash }) 77 | 78 | // Means we have cycled back to the first replica. 79 | if idx == len(m.keys) { 80 | idx = 0 81 | } 82 | 83 | return m.hashMap[m.keys[idx]] 84 | } 85 | -------------------------------------------------------------------------------- /pkg/daemon/attr_unix.go: -------------------------------------------------------------------------------- 1 | package daemon 2 | 3 | import "syscall" 4 | 5 | func NewSysProcAttr() *syscall.SysProcAttr { 6 | return &syscall.SysProcAttr{ 7 | Chroot: "/", 8 | Setsid:true, 9 | } 10 | } -------------------------------------------------------------------------------- /pkg/daemon/attr_windows.go: -------------------------------------------------------------------------------- 1 | package daemon 2 | 3 | 4 | import "syscall" 5 | 6 | func NewSysProcAttr() *syscall.SysProcAttr { 7 | return &syscall.SysProcAttr{ 8 | HideWindow: true, 9 | } 10 | } -------------------------------------------------------------------------------- /pkg/daemon/daemon.go: -------------------------------------------------------------------------------- 1 | package daemon 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "os/exec" 8 | "strconv" 9 | "time" 10 | "syscall" 11 | ) 12 | 13 | const ENV_NAME = "LXW_DAEMON_IDX" 14 | 15 | //运行时调用background的次数 16 | var runIdx int = 0 17 | 18 | type Daemon struct { 19 | pid int 20 | cpid int 21 | } 22 | 23 | func NewDaemon() *Daemon { 24 | return &Daemon{} 25 | } 26 | 27 | func (self *Daemon) Start() { 28 | Background(true) 29 | 30 | for { 31 | cmd, err := Background(false) 32 | if err != nil { 33 | log.Println("start proc err:", err) 34 | time.Sleep(time.Second) 35 | continue 36 | 37 | } 38 | 39 | // self.cpid = cmd.Process.Pid 40 | err = cmd.Wait() 41 | if err != nil { 42 | log.Println("sub procss exit err:", err) 43 | time.Sleep(time.Second) 44 | } 45 | } 46 | } 47 | 48 | // auto Start 是否自动重启 49 | func Background(isExit bool) (cmd *exec.Cmd, err error) { 50 | 51 | var runIdx int = 0 52 | 53 | envIdx, err := strconv.Atoi(os.Getenv(ENV_NAME)) 54 | if err != nil { 55 | envIdx = 0 56 | } 57 | if runIdx > envIdx { //子进程, 退出 58 | return nil, err 59 | } 60 | 61 | //设置子进程环境变量 62 | env := os.Environ() 63 | env = append(env, fmt.Sprintf("%s=%d", ENV_NAME, runIdx)) 64 | 65 | //启动子进程 66 | cmd, err = startProc(os.Args, env) 67 | if err != nil { 68 | log.Println(os.Getpid(), "启动子进程失败:", err) 69 | return nil, err 70 | } 71 | 72 | if isExit { 73 | syscall.Umask(0x00); 74 | os.Exit(0) 75 | } 76 | 77 | return cmd, nil 78 | } 79 | 80 | func startProc(args, env []string) (*exec.Cmd, error) { 81 | cmd := &exec.Cmd{ 82 | Path: args[0], 83 | Args: args, 84 | Env: env, 85 | SysProcAttr: NewSysProcAttr(), 86 | } 87 | 88 | err := cmd.Start() 89 | if err != nil { 90 | return nil, err 91 | } 92 | return cmd, nil 93 | } 94 | -------------------------------------------------------------------------------- /pkg/daemon/test/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | ) 8 | 9 | func main() { 10 | rp, _ := io.Pipe() 11 | 12 | data := make([]byte, 1024) 13 | for { 14 | _, err := rp.Read(data) 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | fmt.Println("data:", string(data)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pkg/dcron/driver.go: -------------------------------------------------------------------------------- 1 | package dcron 2 | 3 | import "time" 4 | 5 | //Driver is a driver interface 6 | type Driver interface { 7 | // Ping is check dirver is valid 8 | Ping() error 9 | SetHeartBeat(nodeID string) 10 | SetTimeout(timeout time.Duration) 11 | GetServiceNodeList(ServiceName string) ([]string, error) 12 | RegisterServiceNode(ServiceName string) (string, error) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/dcron/job_warpper.go: -------------------------------------------------------------------------------- 1 | package dcron 2 | 3 | import "github.com/robfig/cron/v3" 4 | 5 | type Job interface { 6 | Run() 7 | } 8 | 9 | //JobWarpper is a job warpper 10 | type JobWarpper struct { 11 | ID cron.EntryID 12 | Dcron *Dcron 13 | Name string 14 | CronStr string 15 | Func func() 16 | Job Job 17 | } 18 | 19 | //Run is run job 20 | func (job JobWarpper) Run() { 21 | //如果该任务分配给了这个节点 则允许执行 22 | if job.Dcron.allowThisNodeRun(job.Name) { 23 | if job.Func != nil { 24 | job.Func() 25 | } 26 | if job.Job != nil { 27 | job.Job.Run() 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pkg/dcron/node_pool.go: -------------------------------------------------------------------------------- 1 | package dcron 2 | 3 | import ( 4 | "go-ops/pkg/consistenthash" 5 | 6 | "sync" 7 | "time" 8 | ) 9 | 10 | //NodePool is a node pool 11 | type NodePool struct { 12 | serviceName string 13 | NodeID string 14 | 15 | mu sync.Mutex 16 | nodes *consistenthash.Map 17 | 18 | Driver Driver 19 | hashReplicas int 20 | hashFn consistenthash.Hash 21 | updateDuration time.Duration 22 | 23 | dcron *Dcron 24 | } 25 | 26 | func newNodePool(serverName string, driver Driver, dcron *Dcron, updateDuration time.Duration, hashReplicas int) *NodePool { 27 | 28 | err := driver.Ping() 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | nodePool := &NodePool{ 34 | Driver: driver, 35 | serviceName: serverName, 36 | dcron: dcron, 37 | hashReplicas: hashReplicas, 38 | updateDuration: updateDuration, 39 | } 40 | return nodePool 41 | } 42 | 43 | func (np *NodePool) StartPool() error { 44 | var err error 45 | np.Driver.SetTimeout(np.updateDuration) 46 | np.NodeID, err = np.Driver.RegisterServiceNode(np.serviceName) 47 | if err != nil { 48 | return err 49 | } 50 | np.Driver.SetHeartBeat(np.NodeID) 51 | 52 | err = np.updatePool() 53 | if err != nil { 54 | return err 55 | } 56 | 57 | go np.tickerUpdatePool() 58 | return nil 59 | } 60 | 61 | func (np *NodePool) updatePool() error { 62 | np.mu.Lock() 63 | defer np.mu.Unlock() 64 | nodes, err := np.Driver.GetServiceNodeList(np.serviceName) 65 | if err != nil { 66 | return err 67 | } 68 | np.nodes = consistenthash.New(np.hashReplicas, np.hashFn) 69 | for _, node := range nodes { 70 | np.nodes.Add(node) 71 | } 72 | return nil 73 | } 74 | func (np *NodePool) tickerUpdatePool() { 75 | tickers := time.NewTicker(np.updateDuration) 76 | for range tickers.C { 77 | if np.dcron.isRun { 78 | err := np.updatePool() 79 | if err != nil { 80 | np.dcron.err("update node pool error %+v", err) 81 | } 82 | } else { 83 | tickers.Stop() 84 | return 85 | } 86 | } 87 | } 88 | 89 | //PickNodeByJobName : 使用一致性hash算法根据任务名获取一个执行节点 90 | func (np *NodePool) PickNodeByJobName(jobName string) string { 91 | np.mu.Lock() 92 | defer np.mu.Unlock() 93 | if np.nodes.IsEmpty() { 94 | return "" 95 | } 96 | return np.nodes.Get(jobName) 97 | } 98 | -------------------------------------------------------------------------------- /pkg/dcron/option.go: -------------------------------------------------------------------------------- 1 | package dcron 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/robfig/cron/v3" 7 | ) 8 | 9 | type Option func(*Dcron) 10 | 11 | // WithLogger both set dcron and cron logger. 12 | func WithLogger(logger interface{ Printf(string, ...interface{}) }) Option { 13 | return func(dcron *Dcron) { 14 | //set dcron logger 15 | dcron.logger = logger 16 | //set cron logger 17 | f := cron.WithLogger(cron.PrintfLogger(logger)) 18 | dcron.crOptions = append(dcron.crOptions, f) 19 | } 20 | } 21 | 22 | // WithNodeUpdateDuration set node update duration 23 | func WithNodeUpdateDuration(d time.Duration) Option { 24 | return func(dcron *Dcron) { 25 | dcron.nodeUpdateDuration = d 26 | } 27 | } 28 | 29 | // WithHashReplicas set hashReplicas 30 | func WithHashReplicas(d int) Option { 31 | return func(dcron *Dcron) { 32 | dcron.hashReplicas = d 33 | } 34 | } 35 | 36 | //CronOptionLocation is warp cron with location 37 | func CronOptionLocation(loc *time.Location) Option { 38 | return func(dcron *Dcron) { 39 | f := cron.WithLocation(loc) 40 | dcron.crOptions = append(dcron.crOptions, f) 41 | } 42 | } 43 | 44 | //CronOptionSeconds is warp cron with seconds 45 | func CronOptionSeconds() Option { 46 | return func(dcron *Dcron) { 47 | f := cron.WithSeconds() 48 | dcron.crOptions = append(dcron.crOptions, f) 49 | } 50 | } 51 | 52 | // CronOptionParser is warp cron with schedules. 53 | func CronOptionParser(p cron.ScheduleParser) Option { 54 | return func(dcron *Dcron) { 55 | f := cron.WithParser(p) 56 | dcron.crOptions = append(dcron.crOptions, f) 57 | } 58 | } 59 | 60 | // CronOptionChain is Warp cron with chain 61 | func CronOptionChain(wrappers ...cron.JobWrapper) Option { 62 | return func(dcron *Dcron) { 63 | f := cron.WithChain(wrappers...) 64 | dcron.crOptions = append(dcron.crOptions, f) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkg/errors/error.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type ComplexError struct { 9 | Err error 10 | Cause error 11 | } 12 | 13 | func (e ComplexError) Error() string { 14 | return fmt.Sprintf("%s: %s", e.Err.Error(), e.Cause.Error()) 15 | } 16 | 17 | func Error(msg string) error { 18 | return errors.New(msg) 19 | } 20 | 21 | func Errorf(msg string, args ...interface{}) error { 22 | return fmt.Errorf(msg, args...) 23 | } 24 | 25 | func WrapError(cause error, msg string) error { 26 | return WrapComplexError(cause, Error(msg)) 27 | } 28 | 29 | func WrapErrorf(cause error, msg string, args ...interface{}) error { 30 | return WrapComplexError(cause, Errorf(msg, args...)) 31 | } 32 | 33 | func WrapComplexError(cause, err error) error { 34 | if cause == nil { 35 | cause = Error("") 36 | } 37 | 38 | return ComplexError{ 39 | Err: err, 40 | Cause: cause, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "time" 7 | 8 | "go.uber.org/zap" 9 | "go.uber.org/zap/zapcore" 10 | 11 | "github.com/imdario/mergo" 12 | rotatelogs "github.com/lestrrat-go/file-rotatelogs" 13 | ) 14 | 15 | type Logger interface { 16 | Debug(args ...interface{}) 17 | Debugf(format string, args ...interface{}) 18 | Info(args ...interface{}) 19 | Infof(format string, args ...interface{}) 20 | Warn(args ...interface{}) 21 | Warnf(format string, args ...interface{}) 22 | Error(args ...interface{}) 23 | Errorf(format string, args ...interface{}) 24 | } 25 | 26 | var zlog *zap.Logger 27 | 28 | type LogCfg struct { 29 | Filename string 30 | Level int 31 | MaxDays int 32 | LogDir string 33 | Maxsize int64 34 | } 35 | 36 | func DefaultLogCfg() *LogCfg { 37 | return &LogCfg{ 38 | Filename: "go-ops.log", 39 | LogDir: "logs", 40 | Maxsize: 1024, 41 | MaxDays: 30, 42 | } 43 | } 44 | 45 | func getEncoder() zapcore.Encoder { 46 | encoderConfig := zap.NewProductionEncoderConfig() 47 | encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 48 | encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder 49 | return zapcore.NewConsoleEncoder(encoderConfig) 50 | } 51 | 52 | func init() { 53 | 54 | encoder := getEncoder() 55 | core := zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.DebugLevel) 56 | zlog = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) 57 | } 58 | 59 | func InitLog(reqCfg *LogCfg) { 60 | 61 | cfg := DefaultLogCfg() 62 | if reqCfg != nil { 63 | err := mergo.Merge(cfg, reqCfg, mergo.WithOverride) 64 | if err != nil { 65 | panic(err) 66 | } 67 | } 68 | 69 | baseLogPath := path.Join(cfg.LogDir, cfg.Filename) 70 | writter, err := rotatelogs.New( 71 | baseLogPath+".%Y-%m-%d", 72 | rotatelogs.WithLinkName(baseLogPath), 73 | rotatelogs.WithMaxAge(time.Hour*24*time.Duration(cfg.MaxDays)), 74 | rotatelogs.WithRotationSize(1024*1024*cfg.Maxsize), 75 | ) 76 | if err != nil { 77 | panic(err) 78 | } 79 | 80 | encoder := getEncoder() 81 | core := zapcore.NewCore(encoder, zapcore.AddSync(writter), zapcore.DebugLevel) 82 | zlog = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) 83 | 84 | } 85 | 86 | func Sync() { 87 | zlog.Sync() 88 | } 89 | 90 | func Debug(args ...interface{}) { 91 | zlog.Sugar().Debug(args...) 92 | } 93 | 94 | func Info(args ...interface{}) { 95 | zlog.Sugar().Debug(args...) 96 | } 97 | 98 | func Warn(args ...interface{}) { 99 | zlog.Sugar().Warn(args...) 100 | } 101 | 102 | func Error(args ...interface{}) { 103 | zlog.Sugar().Error(args...) 104 | } 105 | 106 | func Debugf(f string, args ...interface{}) { 107 | zlog.Sugar().Debugf(f, args...) 108 | } 109 | 110 | func Infof(f string, args ...interface{}) { 111 | zlog.Sugar().Infof(f, args...) 112 | } 113 | 114 | func Warnf(f string, args ...interface{}) { 115 | zlog.Sugar().Warnf(f, args...) 116 | } 117 | 118 | func Errorf(f string, args ...interface{}) { 119 | zlog.Sugar().Errorf(f, args...) 120 | } 121 | -------------------------------------------------------------------------------- /pkg/logger/logger_test.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import "testing" 4 | 5 | func TestLogger(t *testing.T) { 6 | Info("info msg") 7 | Debug("debug msg") 8 | Warn("warn msg") 9 | Error("error msg") 10 | } 11 | 12 | func TestLoggerInit(t *testing.T) { 13 | InitLog(nil) 14 | Info("info msg") 15 | Debug("debug msg") 16 | Warn("warn msg") 17 | Error("error msg") 18 | } 19 | -------------------------------------------------------------------------------- /pkg/message/jsonc.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "encoding/json" 5 | "go-ops/pkg/schema" 6 | 7 | "github.com/luxingwen/pnet/log" 8 | 9 | "github.com/gogo/protobuf/proto" 10 | ) 11 | 12 | type jsonCodec struct { 13 | } 14 | 15 | // 编码器的名称 16 | func (self *jsonCodec) Name() string { 17 | return "json" 18 | } 19 | 20 | // 将结构体编码为JSON的字节数组 21 | func (self *jsonCodec) Encode(msgObj interface{}) (data []byte, err error) { 22 | 23 | v := MessageMetaByMsg(msgObj) 24 | if v == nil { 25 | log.Error("msg is nil meta:", msgObj) 26 | return 27 | } 28 | 29 | b, err := json.Marshal(msgObj) 30 | if err != nil { 31 | log.Error("json marshal err:", err) 32 | return 33 | } 34 | smsg := &schema.Msg{Id: v.ID, Data: b} 35 | 36 | data, err = proto.Marshal(smsg) 37 | 38 | if err != nil { 39 | log.Error("proto marshal err:", err) 40 | return 41 | } 42 | return 43 | 44 | } 45 | 46 | // 将JSON的字节数组解码为结构体 47 | func (self *jsonCodec) Decode(data []byte) (r interface{}, err error) { 48 | 49 | rmsg := &schema.Msg{} 50 | err = proto.Unmarshal(data, rmsg) 51 | if err != nil { 52 | log.Error("proto unmarshal err:", err) 53 | return nil, err 54 | } 55 | 56 | r = MessageMetaByID(rmsg.Id).NewType() 57 | 58 | err = json.Unmarshal(rmsg.Data, r) 59 | return 60 | } 61 | 62 | var JSONCodec = new(jsonCodec) 63 | -------------------------------------------------------------------------------- /pkg/message/message.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "fmt" 5 | "path" 6 | "reflect" 7 | "strings" 8 | ) 9 | 10 | // 消息元信息 11 | type MessageMeta struct { 12 | //Codec Codec // 消息用到的编码 13 | Type reflect.Type // 消息类型, 注册时使用指针类型 14 | 15 | ID uint32 // 消息ID (二进制协议中使用) 16 | 17 | } 18 | 19 | func (self *MessageMeta) TypeName() string { 20 | 21 | if self == nil { 22 | return "" 23 | } 24 | 25 | return self.Type.Name() 26 | } 27 | 28 | func (self *MessageMeta) FullName() string { 29 | 30 | if self == nil { 31 | return "" 32 | } 33 | 34 | var sb strings.Builder 35 | sb.WriteString(path.Base(self.Type.PkgPath())) 36 | sb.WriteString(".") 37 | sb.WriteString(self.Type.Name()) 38 | 39 | return sb.String() 40 | } 41 | 42 | // 创建meta类型的实例 43 | func (self *MessageMeta) NewType() interface{} { 44 | if self.Type == nil { 45 | return nil 46 | } 47 | 48 | return reflect.New(self.Type).Interface() 49 | } 50 | 51 | var ( 52 | // 消息元信息与消息名称,消息ID和消息类型的关联关系 53 | metaByFullName = map[string]*MessageMeta{} 54 | metaByID = map[uint32]*MessageMeta{} 55 | metaByType = map[reflect.Type]*MessageMeta{} 56 | ) 57 | 58 | // 注册消息元信息 59 | func RegisterMessage(meta *MessageMeta) *MessageMeta { 60 | 61 | // 注册时, 统一为非指针类型 62 | if meta.Type.Kind() == reflect.Ptr { 63 | meta.Type = meta.Type.Elem() 64 | } 65 | 66 | if _, ok := metaByType[meta.Type]; ok { 67 | panic(fmt.Sprintf("Duplicate message meta register by type: %d name: %s", meta.ID, meta.Type.Name())) 68 | } else { 69 | metaByType[meta.Type] = meta 70 | } 71 | 72 | if _, ok := metaByFullName[meta.FullName()]; ok { 73 | panic(fmt.Sprintf("Duplicate message meta register by fullname: %s", meta.FullName())) 74 | } else { 75 | metaByFullName[meta.FullName()] = meta 76 | } 77 | 78 | if meta.ID == 0 { 79 | panic("message meta require 'ID' field: " + meta.TypeName()) 80 | } 81 | 82 | if prev, ok := metaByID[meta.ID]; ok { 83 | panic(fmt.Sprintf("Duplicate message meta register by id: %d type: %s, pre type: %s", meta.ID, meta.TypeName(), prev.TypeName())) 84 | } else { 85 | metaByID[meta.ID] = meta 86 | } 87 | return meta 88 | } 89 | 90 | // 根据类型查找消息元信息 91 | func MessageMetaByType(t reflect.Type) *MessageMeta { 92 | 93 | if t == nil { 94 | return nil 95 | } 96 | 97 | if t.Kind() == reflect.Ptr { 98 | t = t.Elem() 99 | } 100 | 101 | if v, ok := metaByType[t]; ok { 102 | return v 103 | } 104 | 105 | return nil 106 | } 107 | 108 | // 根据消息对象获得消息元信息 109 | func MessageMetaByMsg(msg interface{}) *MessageMeta { 110 | 111 | if msg == nil { 112 | return nil 113 | } 114 | 115 | return MessageMetaByType(reflect.TypeOf(msg)) 116 | } 117 | 118 | // 根据id查找消息元信息 119 | func MessageMetaByID(id uint32) *MessageMeta { 120 | if v, ok := metaByID[id]; ok { 121 | return v 122 | } 123 | 124 | return nil 125 | } 126 | -------------------------------------------------------------------------------- /pkg/proto/ops_agent_plugin.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package proto; 3 | option go_package = "../proto"; 4 | 5 | message Request { 6 | bytes body = 1; 7 | } 8 | 9 | message Response { 10 | bytes body = 1; 11 | } 12 | 13 | 14 | service OpsAgentPlugin { 15 | rpc Run(Request) returns (Response); 16 | } 17 | -------------------------------------------------------------------------------- /pkg/schema/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package schema; 4 | 5 | import "github.com/gogo/protobuf/gogoproto/gogo.proto"; 6 | 7 | 8 | option (gogoproto.gostring_all) = true; 9 | option (gogoproto.goproto_stringer_all) = false; 10 | option (gogoproto.stringer_all) = true; 11 | option (gogoproto.marshaler_all) = true; 12 | option (gogoproto.sizer_all) = true; 13 | option (gogoproto.unmarshaler_all) = true; 14 | 15 | // For tests 16 | option (gogoproto.testgen_all) = true; 17 | option (gogoproto.equal_all) = true; 18 | option (gogoproto.populate_all) = true; 19 | 20 | message Msg { 21 | uint32 id = 1; 22 | bytes data = 2; 23 | } 24 | -------------------------------------------------------------------------------- /pkg/stat/stat.go: -------------------------------------------------------------------------------- 1 | package stat 2 | 3 | import ( 4 | "github.com/shirou/gopsutil/v3/cpu" 5 | "github.com/shirou/gopsutil/v3/disk" 6 | "github.com/shirou/gopsutil/v3/host" 7 | "github.com/shirou/gopsutil/v3/mem" 8 | "github.com/shirou/gopsutil/v3/net" 9 | ) 10 | 11 | type Stat struct { 12 | HostInfo *host.InfoStat 13 | Swapmem *mem.SwapMemoryStat // 交换内存信息 14 | Mem *mem.VirtualMemoryStat 15 | CpuInfo []cpu.InfoStat 16 | DiskUseInfo *disk.UsageStat 17 | Interfaces []net.InterfaceStat 18 | } 19 | 20 | func GetStat() *Stat { 21 | vm, svm := MemInfo() 22 | return &Stat{ 23 | CpuInfo: CpuInfo(), 24 | Mem: vm, 25 | Swapmem: svm, 26 | DiskUseInfo: DiskUsage(), 27 | Interfaces: Interfaces(), 28 | HostInfo: HostInfos(), 29 | } 30 | } 31 | 32 | func CpuInfo() []cpu.InfoStat { 33 | r, _ := cpu.Info() 34 | return r 35 | } 36 | 37 | func MemInfo() (vm *mem.VirtualMemoryStat, svm *mem.SwapMemoryStat) { 38 | vm, _ = mem.VirtualMemory() 39 | svm, _ = mem.SwapMemory() 40 | return 41 | } 42 | 43 | func DiskUsage() (r *disk.UsageStat) { 44 | r, _ = disk.Usage("/") 45 | return 46 | } 47 | 48 | func Interfaces() (r []net.InterfaceStat) { 49 | r, _ = net.Interfaces() 50 | return 51 | } 52 | 53 | func HostInfos() (r *host.InfoStat) { 54 | r, _ = host.Info() 55 | return 56 | } 57 | -------------------------------------------------------------------------------- /pkg/system/cmd_runner.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "context" 5 | "io" 6 | ) 7 | 8 | type Command struct { 9 | User string 10 | Name string 11 | Args []string 12 | Env map[string]string 13 | UseIsolatedEnv bool 14 | 15 | WorkingDir string 16 | 17 | // 只有在linux生效 18 | KeepAttached bool 19 | 20 | Timeout int 21 | 22 | Stdin io.Reader 23 | 24 | Stdout io.Writer 25 | Stderr io.Writer 26 | } 27 | 28 | type Process interface { 29 | Wait(context.Context) Result 30 | } 31 | 32 | type ExitWay int 33 | 34 | const ( 35 | EXITWAY_TIMEOUT ExitWay = 1 36 | EXITWAY_CANCEL ExitWay = 2 37 | ) 38 | 39 | type Result struct { 40 | Stdout string 41 | Stderr string 42 | 43 | ExitStatus int 44 | Error error 45 | ExitWay ExitWay 46 | } 47 | 48 | type CmdRunner interface { 49 | RunComplexCommand(cmd Command) (stdout, stderr string, exitStatus int, exitWay ExitWay, err error) 50 | 51 | RunComplexCommandAsync(cmd Command) (Process, error) 52 | 53 | RunCommand(cmdName string, args ...string) (stdout, stderr string, exitStatus int, exitWay ExitWay, err error) 54 | 55 | RunCommandWithInput(input, cmdName string, args ...string) (stdout, stderr string, exitStatus int, exitWay ExitWay, err error) 56 | 57 | CommandExists(cmdName string) (exists bool) 58 | } 59 | -------------------------------------------------------------------------------- /pkg/system/exec_cmd_runner_unix.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "os/exec" 5 | "strings" 6 | ) 7 | 8 | func newExecCmd(name string, args ...string) *exec.Cmd { 9 | return exec.Command(name, args...) 10 | } 11 | 12 | func mergeEnv(sysEnv []string, cmdEnv map[string]string) []string { 13 | var env []string 14 | for k, v := range cmdEnv { 15 | env = append(env, k+"="+v) 16 | } 17 | for _, s := range sysEnv { 18 | if n := strings.IndexByte(s, '='); n != -1 { 19 | k := s[:n] // key 20 | if _, found := cmdEnv[k]; !found { 21 | env = append(env, s) 22 | } 23 | } 24 | } 25 | return env 26 | } 27 | -------------------------------------------------------------------------------- /pkg/system/exec_cmd_runner_windows.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "os/exec" 5 | "sort" 6 | "strings" 7 | ) 8 | 9 | func newExecCmd(name string, args ...string) *exec.Cmd { 10 | return exec.Command(name, args...) 11 | } 12 | 13 | func mergeEnv(sysEnv []string, cmdEnv map[string]string) []string { 14 | 15 | keys := make([]string, 0, len(cmdEnv)) 16 | for k := range cmdEnv { 17 | keys = append(keys, k) 18 | } 19 | sort.Strings(keys) 20 | 21 | var env []string 22 | seen := make(map[string]bool) // seen env keys 23 | 24 | for _, k := range keys { 25 | v := cmdEnv[k] // value 26 | uk := strings.ToUpper(k) 27 | if !seen[uk] { 28 | env = append(env, k+"="+v) 29 | seen[uk] = true 30 | } 31 | } 32 | for _, kv := range sysEnv { 33 | if n := strings.IndexByte(kv, '='); n != -1 { 34 | k := kv[:n] // key 35 | uk := strings.ToUpper(k) 36 | if !seen[uk] { 37 | env = append(env, kv) 38 | seen[uk] = true 39 | } 40 | } 41 | } 42 | return env 43 | } 44 | -------------------------------------------------------------------------------- /pkg/system/exec_error.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const ( 8 | execErrorMsgFmt = "Running command: '%s', stdout: '%s', stderr: '%s'" 9 | ) 10 | 11 | type ExecError struct { 12 | Command string 13 | StdOut string 14 | StdErr string 15 | } 16 | 17 | func NewExecError(cmd, stdout, stderr string) ExecError { 18 | return ExecError{ 19 | Command: cmd, 20 | StdOut: stdout, 21 | StdErr: stderr, 22 | } 23 | } 24 | 25 | func (e ExecError) Error() string { 26 | return fmt.Sprintf(execErrorMsgFmt, e.Command, e.StdOut, e.StdErr) 27 | } 28 | -------------------------------------------------------------------------------- /pkg/system/exec_process.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "os/exec" 7 | "strings" 8 | "syscall" 9 | "time" 10 | 11 | "go-ops/pkg/errors" 12 | ) 13 | 14 | const ( 15 | execProcessLogTag = "Cmd Runner" 16 | ) 17 | 18 | type execProcess struct { 19 | cmd *exec.Cmd 20 | stdoutWriter *bytes.Buffer 21 | stderrWriter *bytes.Buffer 22 | keepAttached bool 23 | pid int 24 | pgid int 25 | //logger boshlog.Logger 26 | waitCh chan Result 27 | timeout int 28 | } 29 | 30 | func NewExecProcess(cmd *exec.Cmd, keepAttached bool, timeout int) *execProcess { 31 | return &execProcess{ 32 | cmd: cmd, 33 | stdoutWriter: bytes.NewBufferString(""), 34 | stderrWriter: bytes.NewBufferString(""), 35 | keepAttached: keepAttached, 36 | timeout: timeout, 37 | } 38 | } 39 | 40 | func (p *execProcess) Wait(ctx context.Context) (res Result) { 41 | if p.waitCh != nil { 42 | panic("Wait() must be called only once") 43 | } 44 | 45 | if p.timeout == 0 { 46 | p.timeout = 3600 47 | } 48 | 49 | done := make(chan error) 50 | go func() { 51 | done <- p.cmd.Wait() 52 | }() 53 | 54 | after := time.After(time.Duration(p.timeout) * time.Second) 55 | select { 56 | case <-after: 57 | syscall.Kill(-p.cmd.Process.Pid, syscall.SIGKILL) 58 | res = p.getResult() 59 | res.ExitWay = EXITWAY_TIMEOUT 60 | return res 61 | 62 | case <-ctx.Done(): 63 | syscall.Kill(-p.cmd.Process.Pid, syscall.SIGKILL) 64 | res = p.getResult() 65 | res.ExitWay = EXITWAY_CANCEL 66 | return res 67 | case err := <-done: 68 | res = p.getResult() 69 | if err != nil { 70 | cmdString := strings.Join(p.cmd.Args, " ") 71 | err = errors.WrapComplexError(err, NewExecError(cmdString, res.Stdout, res.Stderr)) 72 | res.Error = err 73 | } 74 | return res 75 | } 76 | 77 | return 78 | } 79 | 80 | func (p *execProcess) getResult() Result { 81 | stdout := string(p.stdoutWriter.Bytes()) 82 | 83 | stderr := string(p.stderrWriter.Bytes()) 84 | 85 | exitStatus := -1 86 | 87 | if p.cmd != nil && p.cmd.ProcessState != nil { 88 | waitStatus := p.cmd.ProcessState.Sys().(syscall.WaitStatus) 89 | 90 | if waitStatus.Exited() { 91 | exitStatus = waitStatus.ExitStatus() 92 | } else if waitStatus.Signaled() { 93 | exitStatus = 128 + int(waitStatus.Signal()) 94 | } 95 | } 96 | 97 | return Result{ 98 | Stdout: stdout, 99 | Stderr: stderr, 100 | ExitStatus: exitStatus, 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /pkg/system/exec_process_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package system 4 | 5 | import ( 6 | "strings" 7 | "syscall" 8 | 9 | "go-ops/pkg/errors" 10 | ) 11 | 12 | func (p *execProcess) Start() error { 13 | if p.cmd.Stdout == nil { 14 | p.cmd.Stdout = p.stdoutWriter 15 | } 16 | 17 | if p.cmd.Stderr == nil { 18 | p.cmd.Stderr = p.stderrWriter 19 | } 20 | 21 | cmdString := strings.Join(p.cmd.Args, " ") 22 | //p.logger.Debug(execProcessLogTag, "Running command '%s'", cmdString) 23 | 24 | if !p.keepAttached { 25 | p.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} 26 | } 27 | 28 | err := p.cmd.Start() 29 | if err != nil { 30 | return errors.WrapErrorf(err, "Starting command '%s'", cmdString) 31 | } 32 | 33 | if !p.keepAttached { 34 | p.pgid = p.cmd.Process.Pid 35 | } else { 36 | p.pgid, err = syscall.Getpgid(p.pid) 37 | if err != nil { 38 | 39 | //p.logger.Error(execProcessLogTag, "Failed to retrieve pgid for command '%s'", cmdString) 40 | p.pgid = -1 41 | } 42 | } 43 | 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /pkg/system/exec_process_windows.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "strings" 5 | "time" 6 | 7 | "go-ops/pkg/errors" 8 | ) 9 | 10 | func (p *execProcess) Start() error { 11 | if p.cmd.Stdout == nil { 12 | p.cmd.Stdout = p.stdoutWriter 13 | } 14 | if p.cmd.Stderr == nil { 15 | p.cmd.Stderr = p.stderrWriter 16 | } 17 | cmdString := strings.Join(p.cmd.Args, " ") 18 | //p.logger.Debug(execProcessLogTag, "Running command: %s", cmdString) 19 | 20 | err := p.cmd.Start() 21 | if err != nil { 22 | return errors.WrapErrorf(err, "Starting command %s", cmdString) 23 | } 24 | 25 | p.pid = p.cmd.Process.Pid 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /pkg/util/codec.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | // 字符串转为16位整形哈希 4 | func StringHash(s string) (hash uint16) { 5 | 6 | for _, c := range s { 7 | 8 | ch := uint16(c) 9 | 10 | hash = hash + ((hash) << 5) + ch + (ch << 7) 11 | } 12 | 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /pkg/util/mapreduce.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | func MapReduce(mapper func(interface{}, chan interface{}), 4 | reducer func(chan interface{}, chan interface{}), 5 | input chan interface{}) interface{} { 6 | 7 | reduceInput := make(chan interface{}) 8 | reduceOutput := make(chan interface{}) 9 | workerOutput := make(chan interface{}) 10 | 11 | workProcesses := 0 12 | 13 | go reducer(reduceInput, reduceOutput) 14 | 15 | for item := range input { 16 | go mapper(item, workerOutput) 17 | workProcesses += 1 18 | } 19 | 20 | for item := range workerOutput { 21 | workProcesses -= 1 22 | reduceInput <- item 23 | if workProcesses <= 0 { 24 | close(reduceInput) 25 | break 26 | } 27 | } 28 | return <-reduceOutput 29 | } 30 | -------------------------------------------------------------------------------- /pkg/util/signature.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha1" 6 | "encoding/base64" 7 | ) 8 | 9 | func GetSign(apikey string, seckey string, nonce, timestamp string, body []byte) (r string) { 10 | key := []byte(seckey) 11 | mac := hmac.New(sha1.New, key) 12 | 13 | mac.Write([]byte(apikey)) 14 | mac.Write([]byte(nonce)) 15 | mac.Write([]byte(timestamp)) 16 | mac.Write(body) 17 | r = base64.StdEncoding.EncodeToString(mac.Sum(nil)) 18 | return 19 | } 20 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 13 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /public/script/test.sh: -------------------------------------------------------------------------------- 1 | echo test -------------------------------------------------------------------------------- /resource/i18n/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/i18n/.gitkeep -------------------------------------------------------------------------------- /resource/images/p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/images/p1.png -------------------------------------------------------------------------------- /resource/images/p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/images/p2.png -------------------------------------------------------------------------------- /resource/images/p3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/images/p3.png -------------------------------------------------------------------------------- /resource/images/p4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/images/p4.png -------------------------------------------------------------------------------- /resource/images/pnet1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/images/pnet1.png -------------------------------------------------------------------------------- /resource/public/html/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/public/html/.gitkeep -------------------------------------------------------------------------------- /resource/public/plugin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/public/plugin/.gitkeep -------------------------------------------------------------------------------- /resource/public/resource/css/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/public/resource/css/.gitkeep -------------------------------------------------------------------------------- /resource/public/resource/image/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/public/resource/image/.gitkeep -------------------------------------------------------------------------------- /resource/public/resource/js/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/public/resource/js/.gitkeep -------------------------------------------------------------------------------- /resource/template/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i4de/go-ops/82e1fb0a850b19bbbebd39683d6eafdf70ffbbcc/resource/template/.gitkeep -------------------------------------------------------------------------------- /swagger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Go-ops API DOC 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 50 | 51 | 52 | 53 | 56 | 57 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /test/peer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/luxingwen/pnet" 7 | "github.com/luxingwen/pnet/config" 8 | "github.com/luxingwen/pnet/log" 9 | "github.com/luxingwen/pnet/node" 10 | ) 11 | 12 | func newPnet(id string, name string, port uint16) *pnet.PNet { 13 | 14 | cfg := config.DefaultConfig() 15 | cfg.Hostname = "127.0.0.1" 16 | cfg.Name = "test-peer" 17 | cfg.Port = port 18 | pn, err := pnet.NewPNet(id, cfg) 19 | if err != nil { 20 | panic(err) 21 | } 22 | 23 | pn.ApplyMiddleware(node.LocalNodeStarted{func(lc *node.LocalNode) bool { 24 | lc.SetReady(true) 25 | return true 26 | }, 0}) 27 | 28 | pn.ApplyMiddleware(node.BytesReceived{func(msg, msgID []byte, srcID, rpath string, remoteNode *node.RemoteNode) ([]byte, bool) { 29 | log.Infof("Receive message \"%s\" from %s by %s , path: %s ", string(msg), srcID, remoteNode.Id, rpath) 30 | pn.SendBytesRelayReply(msgID, []byte("receive send res:"+rpath), srcID) 31 | return nil, true 32 | }, 0}) 33 | 34 | err = pn.Start() 35 | if err != nil { 36 | panic(err) 37 | } 38 | 39 | for { 40 | time.Sleep(time.Second) 41 | if pn.GetLocalNode().IsReady() { 42 | return pn 43 | } 44 | } 45 | 46 | return pn 47 | } 48 | 49 | func main() { 50 | hostname := "127.0.0.1" 51 | 52 | p1 := newPnet("p1", hostname, 40001) 53 | p2 := newPnet("p2", hostname, 40002) 54 | p3 := newPnet("p3", hostname, 40003) 55 | p4 := newPnet("p4", hostname, 40004) 56 | p5 := newPnet("p5", hostname, 40005) 57 | p6 := newPnet("p6", hostname, 40006) 58 | 59 | p1.Join("tcp://82.157.165.187:13333") 60 | 61 | p2.Join(p1.GetLocalNode().Addr) 62 | p3.Join(p2.GetLocalNode().Addr) 63 | p4.Join(p3.GetLocalNode().Addr) 64 | p5.Join(p4.GetLocalNode().Addr) 65 | p6.Join(p5.GetLocalNode().Addr) 66 | 67 | select {} 68 | } 69 | -------------------------------------------------------------------------------- /test/py/apps.py: -------------------------------------------------------------------------------- 1 | 2 | # data = \ 3 | # { 4 | # "name": "name1", 5 | # "owner": "owner1" 6 | # } 7 | 8 | import ops 9 | 10 | ospReq = ops.Ops("http://82.157.165.187:30004") 11 | 12 | for i in range(100,200): 13 | data = {} 14 | data['name'] = "name" + str(i) 15 | data['owner'] = "owner" + str(i) 16 | res = ospReq.app_add(data) 17 | 18 | # print(res) 19 | # print("\n") 20 | 21 | print('finish') -------------------------------------------------------------------------------- /test/py/peernode.py: -------------------------------------------------------------------------------- 1 | 2 | import ops 3 | 4 | ospReq = ops.Ops("http://127.0.0.1:8199") 5 | 6 | res = ospReq.peer_nodes({}) 7 | 8 | print(res.json()) -------------------------------------------------------------------------------- /test/py/script.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | data = \ 4 | { 5 | "name": "脚本名称", 6 | "content": "脚本内容", 7 | "args": { 8 | "property1": "", 9 | "property2": "string" 10 | }, 11 | "desc": "我是描述", 12 | "type": "shell", 13 | "creater": "lxw" 14 | } 15 | 16 | 17 | import ops 18 | 19 | 20 | appid = 'adeif00jps0cjq4dq4kf4ys100bqsgp7' 21 | apikey = 'adeif00jps0cjq4dq4kf60t2009dn99jadeif00jps0cjq4dq4kf6am30070yp17' 22 | seckey = 'adeif00jps0cjq4dq4kf6lx400u1hfkoadeif00jps0cjq4dq4kf6v1500ciqss7adeif00jps0cjq4dq4kf73p60007did2adeif00jps0cjq4dq4kf7c4700q1uhbp' 23 | 24 | 25 | ospReq = ops.Ops("http://127.0.0.1:8199", appid, apikey, seckey) 26 | 27 | res = ospReq.script_add(data) 28 | 29 | print(res) 30 | print("\n") 31 | 32 | 33 | # res = ospReq.script_query({}) 34 | 35 | # print(res) 36 | # print("\n") 37 | 38 | # rlist = res['list'] 39 | 40 | # item0 = res['list'][0] 41 | 42 | # item0['name'] = "hkjhjkh" 43 | # item0['scriptId'] = item0["scriptUid"] 44 | 45 | # res = ospReq.script_update(item0) 46 | # print(res) 47 | # print("\n") 48 | 49 | 50 | # res = ospReq.script_query({"name":"hkjhjkh"}) 51 | 52 | # print(res) 53 | # print("\n") 54 | 55 | 56 | # uids = [] 57 | # for item in rlist: 58 | # uids.append(item['scriptUid']) 59 | 60 | # res = ospReq.script_delete({"scriptIds":uids}) 61 | 62 | # print(res) 63 | # print("\n") 64 | -------------------------------------------------------------------------------- /test/py/task_preset.py: -------------------------------------------------------------------------------- 1 | data = \ 2 | { 3 | "type": "string", 4 | "name": "预设任务", 5 | "creater": "luxingwen", 6 | "content": "我是内容hjkjjhkhk" 7 | } 8 | 9 | 10 | import ops 11 | 12 | ospReq = ops.Ops("http://wwh.biggerforum.org:8199") 13 | 14 | for num in range(1, 10): 15 | data["name"] = data["name"] + str(num) 16 | res = ospReq.task_preset_add(data) 17 | print(res) 18 | print('\n') 19 | 20 | res = ospReq.task_preset_query({}) 21 | for item in res['list']: 22 | print(item) 23 | item["name"] = "更新+" + item["name"] 24 | res = ospReq.task_preset_update(item) 25 | print("update:", res) 26 | print("\n") 27 | 28 | --------------------------------------------------------------------------------