mirror of
https://github.com/wgpsec/redc.git
synced 2026-01-24 12:43:19 +08:00
[feat]:update [修改说明]:update
This commit is contained in:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
**/.DS_Store
|
||||
**/.terraform
|
||||
**/.terraform.lock.hcl
|
||||
**/.terraform.tfstate.lock.info
|
||||
**/*.tfstate
|
||||
**/*.tfstate.backup
|
||||
**/*.tar.gz
|
||||
**/temp_ip.txt
|
||||
**/temp_part2.txt
|
||||
**/temp_part4.txt
|
||||
**/config.yaml
|
||||
**/*.jar
|
||||
.idea
|
||||
dist/
|
||||
31
.goreleaser.yaml
Normal file
31
.goreleaser.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
project_name: redc
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
id: "redc"
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
archives:
|
||||
- replacements:
|
||||
darwin: Darwin
|
||||
linux: Linux
|
||||
windows: Windows
|
||||
386: i386
|
||||
amd64: x86_64
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: "v1.3"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
146
README.md
146
README.md
@@ -1 +1,145 @@
|
||||
# redc
|
||||
# redc
|
||||
|
||||
## 编译
|
||||
|
||||
```
|
||||
goreleaser --snapshot --skip-publish --rm-dist
|
||||
```
|
||||
|
||||
## 安装依赖工具
|
||||
|
||||
**mac**
|
||||
```bash
|
||||
brew install aliyun-cli
|
||||
brew install terraform
|
||||
brew install jq
|
||||
```
|
||||
|
||||
**linux**
|
||||
```bash
|
||||
# terraform
|
||||
mkdir -p /tmp/terraform && cd /tmp/terraform && wget -O terraform_1.6.6_linux_amd64.zip 'https://releases.hashicorp.com/terraform/1.6.6/terraform_1.6.6_linux_amd64.zip'
|
||||
unzip terraform_1.6.6_linux_amd64.zip
|
||||
mv --force terraform /usr/local/bin/terraform > /dev/null 2>&1 && chmod +x /usr/local/bin/terraform
|
||||
rm -rf /tmp/terraform
|
||||
|
||||
# 如果是 arm64 机器
|
||||
# mkdir -p /tmp/terraform && cd /tmp/terraform && wget -O terraform_1.6.6_linux_arm64.zip 'https://releases.hashicorp.com/terraform/1.6.6/terraform_1.6.6_linux_arm64.zip'
|
||||
# unzip terraform_1.6.6_linux_arm64.zip
|
||||
# mv --force terraform /usr/local/bin/terraform > /dev/null 2>&1 && chmod +x /usr/local/bin/terraform
|
||||
# rm -rf /tmp/terraform
|
||||
|
||||
cd /tmp
|
||||
terraform -version
|
||||
|
||||
# aliyun
|
||||
mkdir -p /tmp/aliyuncli && cd /tmp/aliyuncli && wget -O aliyun-cli-linux-latest-amd64.tgz 'https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz?file=aliyun-cli-linux-latest-amd64.tgz'
|
||||
tar -xzvf aliyun-cli-linux-latest-amd64.tgz
|
||||
mv --force aliyun /usr/local/bin/aliyun > /dev/null 2>&1 && chmod +x /usr/local/bin/aliyun
|
||||
rm -rf /tmp/aliyuncli
|
||||
|
||||
apt install jq || yum install jq
|
||||
|
||||
# aws
|
||||
https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/getting-started-install.html
|
||||
aws configure
|
||||
```
|
||||
|
||||
**windows**
|
||||
```
|
||||
https://github.com/aliyun/aliyun-cli/releases/download/v3.0.121/aliyun-cli-windows-3.0.121-amd64.zip
|
||||
https://releases.hashicorp.com/terraform/1.2.3/terraform_1.2.3_windows_amd64.zip
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
```bash
|
||||
aliyun configure set --profile cloud-tool --mode AK --region cn-beijing --access-key-id xxxxxxxxxxxxxx --access-key-secret xxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
配置tf插件缓存路径
|
||||
```bash
|
||||
echo 'plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"' > ~/.terraformrc
|
||||
```
|
||||
|
||||
使用前需初始化redc,将自动下载tf模块依赖
|
||||
```
|
||||
./redc -init
|
||||
```
|
||||
|
||||
## 思路
|
||||
|
||||
1. 先创建新项目
|
||||
2. 指定项目下要创建场景会从场景库复制一份场景文件夹到项目文件夹下
|
||||
3. 不同项目下创建同一场景互不干扰
|
||||
4. 同一项目下创建同一场景互不干扰
|
||||
5. 多用户操作互不干扰(本地有做鉴权,但这个实际上要在平台上去做)
|
||||
|
||||
- redc 配置文件 (.redc.ini)
|
||||
- 项目1 (./project1)
|
||||
- 场景1 (./project1/[uuid1])
|
||||
- main.tf
|
||||
- version.tf
|
||||
- output.tf
|
||||
- 场景2 (./project1/[uuid2])
|
||||
- main.tf
|
||||
- version.tf
|
||||
- output.tf
|
||||
- 项目状态文件 (project.ini)
|
||||
- 项目2 (./project2)
|
||||
- 场景1 (./project2/[uuid1])
|
||||
- main.tf
|
||||
- version.tf
|
||||
- output.tf
|
||||
- 场景2 (./project2/[uuid2])
|
||||
- ...
|
||||
- 项目状态文件 (project.ini)
|
||||
- 项目3 (./project3)
|
||||
- ...
|
||||
|
||||
## 交互
|
||||
|
||||
```bash
|
||||
# 项目 test 开启 awvs 场景
|
||||
redc -project test -start awvs -u zhangsan
|
||||
.........
|
||||
.........
|
||||
项目uuid:xxxxxxxxx
|
||||
|
||||
# 查看 test 项目中指定场景的状态
|
||||
redc -project test -status [uuid] -u zhangsan
|
||||
|
||||
# 关闭 test 项目中指定场景
|
||||
redc -project test -stop [uuid] -u zhangsan
|
||||
|
||||
# 查看 test 项目的所有场景
|
||||
redc -project test -list -u zhangsan
|
||||
uuid type createtime operator
|
||||
xxxxxxxxx awvs 2022.02.22 system
|
||||
bbbbbbbbb file 2022.02.22 system
|
||||
```
|
||||
|
||||
场景名称
|
||||
```
|
||||
awvs
|
||||
file
|
||||
chat
|
||||
c2
|
||||
nessus
|
||||
proxy
|
||||
pupy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 设计规划
|
||||
|
||||
tf 分成 2 类场景
|
||||
- 基础场景
|
||||
- 复杂场景 (由基础场景修改而来)
|
||||
|
||||
redc 考虑是给予平台使用,在平台上由多项目、多用户进行操作,同时兼顾单机版需求
|
||||
|
||||
由于 tf 的局限性,使用时和其文件夹结构脱不开关联,在多用户的情况下需要用 Backend 同步状态锁,融入到平台虽然可以用 Consul 解决多用户操作的问题,但多项目下要使用依然无法解决
|
||||
|
||||
无法让多项目用1个文件夹场景,如果多复制几个文件夹太过笨重。。。这些都不够高效率
|
||||
|
||||
17
go.mod
Normal file
17
go.mod
Normal file
@@ -0,0 +1,17 @@
|
||||
module red-cloud
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/beevik/ntp v1.0.0
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
|
||||
golang.org/x/text v0.9.0
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/net v0.9.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
)
|
||||
69
go.sum
Normal file
69
go.sum
Normal file
@@ -0,0 +1,69 @@
|
||||
github.com/beevik/ntp v1.0.0 h1:d0Lgy1xbNNqVyGfvg2Z96ItKcfyn3lzgus/oRoj9vnk=
|
||||
github.com/beevik/ntp v1.0.0/go.mod h1:JN7/74B0Z4GUGO/1aUeRI2adARlfJGUeaJb0y0Wvnf4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
199
main.go
Normal file
199
main.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/beevik/ntp"
|
||||
"os"
|
||||
"os/exec"
|
||||
redc "red-cloud/mod"
|
||||
"red-cloud/mod2"
|
||||
"red-cloud/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ProjectPath = "./redc-taskresult"
|
||||
|
||||
func main() {
|
||||
|
||||
// ntp校验
|
||||
//CheckStatus()
|
||||
flag.Parse()
|
||||
|
||||
if redc.Debug {
|
||||
DebugFunc()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// -version 显示版本号
|
||||
if redc.V {
|
||||
fmt.Println(redc.Version)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// 解析配置(暂时不需要这一步)
|
||||
// redc.LoadConfig(configPath)
|
||||
|
||||
// -init 初始化
|
||||
if redc.Init {
|
||||
redc.RedcLog("进行初始化")
|
||||
fmt.Println("初始化中")
|
||||
// 先删除文件夹
|
||||
err := os.RemoveAll("redc-templates")
|
||||
mod2.PrintOnError(err, "初始化过程中删除模板文件夹失败")
|
||||
// 释放templates资源
|
||||
utils.ReleaseDir("redc-templates")
|
||||
|
||||
// 遍历 redc-templates 文件夹,不包括子目录
|
||||
_, dirs := utils.GetFilesAndDirs("./redc-templates")
|
||||
for _, v := range dirs {
|
||||
redc.TfInit0(v)
|
||||
}
|
||||
|
||||
// 遍历 redc-templates 文件夹,包括子目录 (现已被替代)
|
||||
/*dirs := utils.ChechDirMain("./redc-templates")
|
||||
for _, v := range dirs {
|
||||
err := utils.CheckFileName(v, "tf")
|
||||
if err {
|
||||
fmt.Println(v)
|
||||
redc.TfInit(v)
|
||||
}
|
||||
}*/
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// 解析项目名称
|
||||
redc.ProjectParse(ProjectPath+"/"+redc.Project, redc.Project, redc.U)
|
||||
|
||||
// list 操作查看项目里所有 case
|
||||
if redc.List {
|
||||
redc.CaseList(ProjectPath + "/" + redc.Project)
|
||||
}
|
||||
|
||||
if redc.Cost {
|
||||
redc.RedcLog("查看余额")
|
||||
fmt.Print("阿里云当前余额: ")
|
||||
err := utils.Command("aliyun bssopenapi QueryAccountBalance --region cn-beijing | jq -r .Data.AvailableAmount")
|
||||
if err != nil {
|
||||
fmt.Println("查询阿里云当前余额失败!", err)
|
||||
}
|
||||
|
||||
fmt.Print("华为云当前余额: ")
|
||||
err2 := utils.Command("hcloud BSS ShowCustomerAccountBalances --cli-region=\"cn-north-1\" | jq .account_balances | jq '.[1] | .amount'")
|
||||
if err2 != nil {
|
||||
fmt.Println("查询华为云当前余额失败!", err2)
|
||||
}
|
||||
|
||||
fmt.Print("腾讯云当前余额: ")
|
||||
err3 := utils.Command("tccli billing DescribeAccountBalance --cli-unfold-argument | jq '.Balance | tonumber/100'")
|
||||
if err3 != nil {
|
||||
fmt.Println("查询腾讯云当前余额失败!", err3)
|
||||
}
|
||||
}
|
||||
|
||||
if redc.Fc {
|
||||
redc.RedcLog("查看云函数余量")
|
||||
// https://next.api.aliyun.com/api/BssOpenApi/2017-12-14/QueryResourcePackageInstances?tab=CLI
|
||||
fmt.Print("阿里云Fc当前余量: \n")
|
||||
err := utils.CommandUTF("aliyun bssopenapi QueryResourcePackageInstances --region cn-beijing | jq .Data.Instances.Instance | jq -r '.[] | \"\\(.Remark): \\(.RemainingAmount) \\(.TotalAmountUnit)\"'")
|
||||
if err != nil {
|
||||
fmt.Println("查询阿里云SCF当前余量失败!", err)
|
||||
}
|
||||
|
||||
fmt.Print("\n腾讯云scf目前不支持查询余量,请到控制台查看. \n")
|
||||
}
|
||||
|
||||
// start 操作,去调用 case 创建方法
|
||||
if redc.Start != "" {
|
||||
redc.RedcLog("start " + redc.Start)
|
||||
if redc.Start == "pte" {
|
||||
redc.Start = "pte_arm"
|
||||
}
|
||||
//fmt.Println("step1")
|
||||
redc.CaseCreate(ProjectPath+"/"+redc.Project, redc.Start, redc.U, redc.Name)
|
||||
}
|
||||
|
||||
// stop 操作,去调用 case 删除方法
|
||||
if redc.Stop != "" {
|
||||
redc.RedcLog("stop " + redc.Stop)
|
||||
redc.CheckUser(ProjectPath+"/"+redc.Project, redc.Stop)
|
||||
redc.CaseStop(ProjectPath+"/"+redc.Project, redc.Stop)
|
||||
}
|
||||
if redc.Kill != "" {
|
||||
redc.CheckUser(ProjectPath+"/"+redc.Project, redc.Kill)
|
||||
redc.CaseKill(ProjectPath+"/"+redc.Project, redc.Kill)
|
||||
}
|
||||
|
||||
// change 操作,去调用 case 更改方法
|
||||
if redc.Change != "" {
|
||||
redc.RedcLog("change " + redc.Change)
|
||||
redc.CheckUser(ProjectPath+"/"+redc.Project, redc.Change)
|
||||
redc.CaseChange(ProjectPath+"/"+redc.Project, redc.Change)
|
||||
}
|
||||
|
||||
// status 操作,去调用 case 状态方法
|
||||
if redc.Status != "" {
|
||||
redc.RedcLog("status" + redc.Status)
|
||||
redc.CheckUser(ProjectPath+"/"+redc.Project, redc.Status)
|
||||
redc.CaseStatus(ProjectPath+"/"+redc.Project, redc.Status)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func DebugFunc() {
|
||||
|
||||
}
|
||||
|
||||
// CheckStatus 有效期,过期后调用自删除
|
||||
func CheckStatus() {
|
||||
now := time.Now()
|
||||
|
||||
// 连接超时时间
|
||||
timeout := 1 * time.Second
|
||||
|
||||
// 尝试连接3次
|
||||
var response *ntp.Response
|
||||
var err error
|
||||
for i := 0; i < 4; i++ {
|
||||
response, err = ntp.QueryWithOptions("ntp1.aliyun.com", ntp.QueryOptions{Timeout: timeout})
|
||||
if err != nil {
|
||||
//fmt.Printf("第 %d 次连接失败: %s\n", i+1, err)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
mod2.ExitOnError(err, "连接 NTP 服务器失败")
|
||||
}
|
||||
|
||||
// 获取当前时间
|
||||
now = time.Now()
|
||||
|
||||
// 计算偏移量
|
||||
offset := response.ClockOffset
|
||||
|
||||
// 校正时间
|
||||
corrected := now.Add(offset)
|
||||
|
||||
// 指定过期时间
|
||||
expireTime := time.Date(2024, 6, 10, 0, 0, 0, 0, time.Local)
|
||||
|
||||
// 比较当前时间和过期时间
|
||||
if corrected.After(expireTime) {
|
||||
fmt.Println("当前时间:", now)
|
||||
fmt.Println("已过期")
|
||||
NoFile()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// NoFile linux落地删、进程隐藏
|
||||
func NoFile() {
|
||||
exePath, _ := os.Executable()
|
||||
cmd := exec.Command("sh", "-c", "rm -f "+exePath)
|
||||
cmd.Start()
|
||||
cmd = exec.Command("sh", "-c", "rm -f nohup.out")
|
||||
cmd.Start()
|
||||
}
|
||||
317
mod/case.go
Normal file
317
mod/case.go
Normal file
@@ -0,0 +1,317 @@
|
||||
package mod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gopkg.in/ini.v1"
|
||||
"math/rand"
|
||||
"os"
|
||||
"red-cloud/utils"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RandomName() string {
|
||||
var lastName = []string{
|
||||
"red", "blue", "yellow", "brown", "purple", "anger", "lazy", "shy", "huge", "rare",
|
||||
"fast", "stupid", "sluggish", "boring", "rigid", "rigorous", "clever", "dexterity",
|
||||
"white", "black", "dark", "idiot", "shiny", "friendly", "integrity", "happy", "sad",
|
||||
"lively", "lonely", "ugly", "leisurely", "calm", "young", "tenacious"}
|
||||
var firstName = []string{
|
||||
"pig", "cow", "sheep", "mouse", "dragon", "serpent", "tiger", "fox", "frog", "chicken",
|
||||
"fish", "shrimp", "hippocampus", "helicopter", "crab", "dolphin", "whale", "chinchilla",
|
||||
"bunny", "mole", "rabbit", "horse", "monkey", "dog", "shark", "panda", "bear", "lion",
|
||||
"rhino", "leopard", "giraffe", "deer", "wolf", "parrot", "camel", "antelope", "turtle", "zebra"}
|
||||
var lastNameLen = len(lastName)
|
||||
var firstNameLen = len(firstName)
|
||||
rand.Seed(time.Now().UnixNano()) //设置随机数种子
|
||||
var first string //名
|
||||
for i := 0; i <= rand.Intn(1); i++ { //随机产生2位或者3位的名
|
||||
first = fmt.Sprint(firstName[rand.Intn(firstNameLen-1)])
|
||||
}
|
||||
return fmt.Sprint(lastName[rand.Intn(lastNameLen-1)]) + first
|
||||
}
|
||||
|
||||
func CaseCreate(ProjectPath string, CaseName string, User string, Name string) {
|
||||
// 创建新的 case 目录,这里不需要检测是否存在,因为名称是采用nanoID
|
||||
u1 := uuid.NewV4()
|
||||
|
||||
// 复制tf文件
|
||||
err := utils.Dir("redc-templates/"+CaseName, ProjectPath+"/"+u1.String())
|
||||
if err != nil {
|
||||
fmt.Println("错误输入")
|
||||
os.Exit(3)
|
||||
} else {
|
||||
fmt.Println("Case 路径", u1.String())
|
||||
}
|
||||
|
||||
// 在次 init,防止万一
|
||||
TfInit(ProjectPath + "/" + u1.String())
|
||||
|
||||
fmt.Println("开始创建")
|
||||
|
||||
// 部分场景单独处理
|
||||
if CaseName == "cs-49" || CaseName == "c2-new" || CaseName == "snowc2" {
|
||||
C2Apply(ProjectPath + "/" + u1.String())
|
||||
} else if CaseName == "aws-proxy" {
|
||||
AwsProxyApply(ProjectPath + "/" + u1.String())
|
||||
} else if CaseName == "ddos" {
|
||||
if Durl == "" {
|
||||
fmt.Printf("ddos目标不可为空")
|
||||
RedcLog("创建失败,ddos目标不可为空")
|
||||
os.Exit(3)
|
||||
}
|
||||
DDOSApply(ProjectPath + "/" + u1.String())
|
||||
} else if CaseName == "aliyun-proxy" {
|
||||
AliyunProxyApply(ProjectPath + "/" + u1.String())
|
||||
} else if CaseName == "dnslog" || CaseName == "xraydnslog" {
|
||||
if Domain == "360.com" {
|
||||
fmt.Printf("创建dnslog时,域名不可为默认值")
|
||||
RedcLog("创建失败,创建dnslog时,域名不可为默认值")
|
||||
os.Exit(3)
|
||||
}
|
||||
DnslogApply(ProjectPath + "/" + u1.String())
|
||||
} else if CaseName == "pss5" || CaseName == "frp" || CaseName == "frp-loki" || CaseName == "nps" {
|
||||
Base64Apply(ProjectPath + "/" + u1.String())
|
||||
} else {
|
||||
TfApply(ProjectPath + "/" + u1.String())
|
||||
}
|
||||
|
||||
// 确认场景创建无误后,才会写入到配置文件中
|
||||
RedcLog("创建成功 " + ProjectPath + u1.String() + " " + CaseName)
|
||||
// case 入库
|
||||
filePath := ProjectPath + "/project.ini"
|
||||
cfg, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
cfg.Section(u1.String()).Key("Operator").SetValue(User)
|
||||
cfg.Section(u1.String()).Key("Type").SetValue(CaseName)
|
||||
currentTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
cfg.Section(u1.String()).Key("CreateTime").SetValue(currentTime)
|
||||
|
||||
if Name == "" {
|
||||
Name = RandomName()
|
||||
}
|
||||
cfg.Section(u1.String()).Key("Name").SetValue(Name)
|
||||
|
||||
// 部分场景单独处理
|
||||
if CaseName == "cs-49" || CaseName == "c2-new" || CaseName == "snowc2" {
|
||||
// 写入节点数量到ini文件
|
||||
cfg.Section(u1.String()).Key("Node").SetValue(strconv.Itoa(Node))
|
||||
cfg.Section(u1.String()).Key("Doamin").SetValue(Domain)
|
||||
} else if CaseName == "aws-proxy" {
|
||||
// 写入节点数量到ini文件
|
||||
cfg.Section(u1.String()).Key("Node").SetValue(strconv.Itoa(Node))
|
||||
} else if CaseName == "ddos" {
|
||||
// 写入节点数量到ini文件
|
||||
cfg.Section(u1.String()).Key("Node").SetValue(strconv.Itoa(Node))
|
||||
} else if CaseName == "aliyun-proxy" {
|
||||
// 写入节点数量到ini文件
|
||||
cfg.Section(u1.String()).Key("Node").SetValue(strconv.Itoa(Node))
|
||||
} else if CaseName == "dnslog" || CaseName == "xraydnslog" {
|
||||
// 写入域名到ini文件
|
||||
cfg.Section(u1.String()).Key("Doamin").SetValue(Domain)
|
||||
} else if CaseName == "pss5" || CaseName == "frp" || CaseName == "frp-loki" || CaseName == "nps" {
|
||||
// 写入base64命令到ini文件
|
||||
cfg.Section(u1.String()).Key("Base64Command").SetValue(Base64Command)
|
||||
}
|
||||
err = cfg.SaveTo(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("写入 ini 时失败: %v", err)
|
||||
RedcLog("写入 ini 时失败")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
fmt.Println("Case 路径", u1.String())
|
||||
}
|
||||
|
||||
func CaseStop(ProjectPath string, UUID string) {
|
||||
|
||||
filePath := ProjectPath + "/project.ini"
|
||||
cfg, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
//fmt.Println(UUID)
|
||||
if cfg.Section(UUID).Key("Type").String() == "cs-49" || cfg.Section(UUID).Key("Type").String() == "c2-new" || cfg.Section(UUID).Key("Type").String() == "snowc2" {
|
||||
C2Destroy(ProjectPath+"/"+UUID,
|
||||
cfg.Section(UUID).Key("Node").String(),
|
||||
cfg.Section(UUID).Key("Domain").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "aws-proxy" {
|
||||
AwsProxyDestroy(ProjectPath+"/"+UUID,
|
||||
cfg.Section(UUID).Key("Node").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "ddos" {
|
||||
DDOSDestroy(ProjectPath+"/"+UUID,
|
||||
cfg.Section(UUID).Key("Node").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "aliyun-proxy" {
|
||||
AliyunProxyDestroy(ProjectPath+"/"+UUID,
|
||||
cfg.Section(UUID).Key("Node").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "dnslog" || cfg.Section(UUID).Key("Type").String() == "xraydnslog" {
|
||||
DnslogDestroy(ProjectPath+"/"+UUID, cfg.Section(UUID).Key("Domain").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "pss5" || cfg.Section(UUID).Key("Type").String() == "frp" || cfg.Section(UUID).Key("Type").String() == "frp-loki" || cfg.Section(UUID).Key("Type").String() == "nps" {
|
||||
Base64Destroy(ProjectPath+"/"+UUID, cfg.Section(UUID).Key("Base64Command").String())
|
||||
} else {
|
||||
TfDestroy(ProjectPath + "/" + UUID)
|
||||
}
|
||||
|
||||
// 成功销毁场景后,删除 case 文件夹
|
||||
err = os.RemoveAll(ProjectPath + "/" + UUID)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
// case 删除
|
||||
cfg2, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
cfg2.DeleteSection(UUID)
|
||||
err = cfg2.SaveTo(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("修改 ini 时失败: %v", err)
|
||||
RedcLog("修改 ini 时失败")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func CaseKill(ProjectPath string, UUID string) {
|
||||
|
||||
filePath := ProjectPath + "/project.ini"
|
||||
cfg, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
// 在次 init,防止万一
|
||||
dirs := utils.ChechDirMain(ProjectPath + "/" + UUID)
|
||||
for _, v := range dirs {
|
||||
err := utils.CheckFileName(v, "tf")
|
||||
if err {
|
||||
TfInit(v)
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Section(UUID).Key("Type").String() == "cs-49" || cfg.Section(UUID).Key("Type").String() == "c2-new" || cfg.Section(UUID).Key("Type").String() == "snowc2" {
|
||||
C2Destroy(ProjectPath+"/"+UUID,
|
||||
cfg.Section(UUID).Key("Node").String(),
|
||||
cfg.Section(UUID).Key("Domain").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "aws-proxy" {
|
||||
AwsProxyDestroy(ProjectPath+"/"+UUID,
|
||||
cfg.Section(UUID).Key("Node").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "aliyun-proxy" {
|
||||
AliyunProxyDestroy(ProjectPath+"/"+UUID,
|
||||
cfg.Section(UUID).Key("Node").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "dnslog" || cfg.Section(UUID).Key("Type").String() == "xraydnslog" {
|
||||
DnslogDestroy(ProjectPath, cfg.Section(UUID).Key("Domain").String())
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "pss5" || cfg.Section(UUID).Key("Type").String() == "frp" || cfg.Section(UUID).Key("Type").String() == "frp-loki" || cfg.Section(UUID).Key("Type").String() == "nps" {
|
||||
Base64Destroy(ProjectPath+"/"+UUID, cfg.Section(UUID).Key("Base64Command").String())
|
||||
} else {
|
||||
TfDestroy(ProjectPath + "/" + UUID)
|
||||
}
|
||||
|
||||
// 成功销毁场景后,删除 case 文件夹
|
||||
err = os.RemoveAll(ProjectPath + "/" + UUID)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
// case 删除
|
||||
cfg2, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
cfg2.DeleteSection(UUID)
|
||||
err = cfg2.SaveTo(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("修改 ini 时失败: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
|
||||
func CaseChange(ProjectPath string, UUID string) {
|
||||
|
||||
filePath := ProjectPath + "/project.ini"
|
||||
cfg, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
if cfg.Section(UUID).Key("Type").String() == "cs-49" || cfg.Section(UUID).Key("Type").String() == "c2-new" || cfg.Section(UUID).Key("Type").String() == "snowc2" {
|
||||
C2Change(ProjectPath + "/" + UUID)
|
||||
} else if cfg.Section(UUID).Key("Type").String() == "aliyun-proxy" {
|
||||
AliyunProxyChange(ProjectPath + "/" + UUID)
|
||||
} else {
|
||||
fmt.Printf("不适用与当前场景")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func CaseStatus(ProjectPath string, UUID string) {
|
||||
filePath := ProjectPath + "/project.ini"
|
||||
cfg, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
fmt.Println("操作人员:", cfg.Section(UUID).Key("Operator").String())
|
||||
fmt.Println("项目名称:", cfg.Section(UUID).Key("Name").String())
|
||||
fmt.Println("场景类型:", cfg.Section(UUID).Key("Type").String())
|
||||
fmt.Println("创建时间:", cfg.Section(UUID).Key("CreateTime").String())
|
||||
|
||||
TfStatus(ProjectPath + "/" + UUID)
|
||||
|
||||
}
|
||||
|
||||
func CaseList(ProjectPath string) {
|
||||
filePath := ProjectPath + "/project.ini"
|
||||
cfg, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 15, 0, 1, ' ',
|
||||
tabwriter.AlignRight)
|
||||
fmt.Fprintln(w, "UUID\tType\tName\tOperator\tCreateTime\t")
|
||||
for i := 1; i < len(cfg.SectionStrings()); i++ {
|
||||
if cfg.Section(cfg.SectionStrings()[i]).Key("Operator").String() == U || U == "system" {
|
||||
fmt.Fprintln(w, cfg.SectionStrings()[i], "\t", cfg.Section(cfg.SectionStrings()[i]).Key("Type").String(), "\t", cfg.Section(cfg.SectionStrings()[i]).Key("Name").String(), "\t", cfg.Section(cfg.SectionStrings()[i]).Key("Operator").String(), "\t", cfg.Section(cfg.SectionStrings()[i]).Key("CreateTime").String())
|
||||
}
|
||||
}
|
||||
err = w.Flush()
|
||||
if err != nil {
|
||||
fmt.Printf("打印失败: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
RandomName()
|
||||
}
|
||||
|
||||
func CheckUser(ProjectPath string, UUID string) {
|
||||
filePath := ProjectPath + "/project.ini"
|
||||
cfg, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
// 鉴权
|
||||
if cfg.Section(UUID).Key("Operator").String() != U && U != "system" {
|
||||
fmt.Printf("用户 %v 无权访问 %v", U, UUID)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
48
mod/config.go
Normal file
48
mod/config.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package mod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopkg.in/ini.v1"
|
||||
"os"
|
||||
)
|
||||
|
||||
// LoadConfig 加载配置文件
|
||||
func LoadConfig(path string) {
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
// 没有配置文件,报错退出,提示进行修改
|
||||
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
fmt.Println("配置文件创建失败", err)
|
||||
} else {
|
||||
fmt.Println("已生成状态文件", path, "请自行修改")
|
||||
|
||||
cfg, err := ini.Load(path)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
cfg.Section("").Key("operator").SetValue("system")
|
||||
cfg.Section("").Key("ALICLOUD_ACCESS_KEY").SetValue("changethis")
|
||||
cfg.Section("").Key("ALICLOUD_SECRET_KEY").SetValue("changethis")
|
||||
cfg.SaveTo(path)
|
||||
}
|
||||
defer file.Close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ParseConfig 解析配置文件
|
||||
func ParseConfig(path string) (string, string) {
|
||||
cfg, err := ini.Load(path)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ALICLOUD_ACCESS_KEY := cfg.Section("").Key("ALICLOUD_ACCESS_KEY").String()
|
||||
ALICLOUD_SECRET_KEY := cfg.Section("").Key("ALICLOUD_SECRET_KEY").String()
|
||||
|
||||
return ALICLOUD_ACCESS_KEY, ALICLOUD_SECRET_KEY
|
||||
}
|
||||
54
mod/flag.go
Normal file
54
mod/flag.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package mod
|
||||
|
||||
import "flag"
|
||||
|
||||
var (
|
||||
V bool
|
||||
Init bool
|
||||
Cost bool
|
||||
Fc bool
|
||||
List bool
|
||||
Debug bool
|
||||
U string
|
||||
Name string
|
||||
Project string
|
||||
Start string
|
||||
Change string
|
||||
Stop string
|
||||
Kill string
|
||||
Status string
|
||||
Node int
|
||||
Domain string
|
||||
Base64Command string
|
||||
Version = "v1.3.2(2024/03/18)(wgpsec)"
|
||||
Durl string
|
||||
Dtime int
|
||||
Dnum int
|
||||
Dmode string
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
flag.BoolVar(&V, "version", false, "显示版本号")
|
||||
flag.BoolVar(&Init, "init", false, "初始化")
|
||||
flag.BoolVar(&Debug, "debug", false, "调试")
|
||||
flag.StringVar(&U, "u", "system", "操作者")
|
||||
flag.StringVar(&Project, "p", "default", "项目名称")
|
||||
flag.BoolVar(&List, "list", false, "查看项目所有场景")
|
||||
flag.BoolVar(&Fc, "fc", false, "查询云函数余量")
|
||||
flag.BoolVar(&Cost, "cost", false, "查看余额")
|
||||
flag.StringVar(&Start, "start", "", "开启case")
|
||||
flag.StringVar(&Kill, "kill", "", "强制关闭case")
|
||||
flag.StringVar(&Stop, "stop", "", "关闭case")
|
||||
flag.StringVar(&Change, "change", "", "更改case状态 (c2场景是切换rg ip,代理池场景是重启代理池)")
|
||||
flag.StringVar(&Status, "status", "", "查看case状态")
|
||||
flag.StringVar(&Name, "name", "", "查看case状态")
|
||||
flag.IntVar(&Node, "node", 10, "机器数量(默认10)")
|
||||
flag.StringVar(&Domain, "domain", "www.amazon.com", "CS/dnslog的监听域名")
|
||||
flag.StringVar(&Base64Command, "base64command", "", "frp/nps服务端配置(base64传入)")
|
||||
flag.StringVar(&Durl, "durl", "", "ddos目标")
|
||||
flag.IntVar(&Dtime, "dtime", 600, "ddos持续时间(默认10分钟)")
|
||||
flag.IntVar(&Dnum, "dnum", 3500, "ddos线程数(默认3500)")
|
||||
flag.StringVar(&Dmode, "dmode", "APACHE", "ddos模式")
|
||||
|
||||
}
|
||||
60
mod/project.go
Normal file
60
mod/project.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package mod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopkg.in/ini.v1"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ProjectParse(ProjectPath string, ProjectName string, User string) {
|
||||
// 确认项目文件夹是否存在,不存在就创建
|
||||
_, err := os.Stat(ProjectPath)
|
||||
if err != nil {
|
||||
// 创建项目目录
|
||||
err := os.MkdirAll(ProjectPath, os.ModePerm)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(3)
|
||||
} else {
|
||||
fmt.Println("已创建项目目录", ProjectPath)
|
||||
}
|
||||
// 创建项目状态文件
|
||||
filePath := ProjectPath + "/project.ini"
|
||||
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
fmt.Println("项目状态文件创建失败", err)
|
||||
} else {
|
||||
fmt.Println("已创建项目状态文件", filePath)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
/*
|
||||
// 写入项目创建时间,创建者
|
||||
cfg, err := ini.Load(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
cfg.Section("Global").Key("ProjectName").SetValue(ProjectName)
|
||||
cfg.Section("Global").Key("ProjectPath").SetValue(ProjectPath)
|
||||
currentTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
cfg.Section("Global").Key("CreateTime").SetValue(currentTime)
|
||||
cfg.Section("Global").Key("Operator").SetValue(User)
|
||||
cfg.SaveTo(filePath)
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ProjectConfigParse(path string) {
|
||||
cfg, err := ini.Load(path)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
fmt.Println("项目名称:", cfg.Section("Global").Key("ProjectName").String())
|
||||
fmt.Println("项目路径:", cfg.Section("Global").Key("ProjectPath").String())
|
||||
fmt.Println("创建时间:", cfg.Section("Global").Key("CreateTime").String())
|
||||
fmt.Println("创建人员:", cfg.Section("Global").Key("Operator").String())
|
||||
}
|
||||
24
mod/redclog.go
Normal file
24
mod/redclog.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package mod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"red-cloud/mod2"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RedcLog 将给定的消息记录到 "redc.log" 文件中。
|
||||
func RedcLog(message string) {
|
||||
// 打开或创建日志文件
|
||||
file, err := os.OpenFile("redc.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
mod2.PrintOnError(err, "failed to open log file")
|
||||
defer file.Close()
|
||||
|
||||
// 获取当前时间作为日志时间戳
|
||||
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
// 构造日志消息并写入文件
|
||||
_, err = file.WriteString(fmt.Sprintf("[%s] %s\n", timestamp, message))
|
||||
mod2.PrintOnError(err, "failed to write to log file")
|
||||
|
||||
}
|
||||
452
mod/tf.go
Normal file
452
mod/tf.go
Normal file
@@ -0,0 +1,452 @@
|
||||
package mod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"red-cloud/mod2"
|
||||
"red-cloud/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 第一次初始化
|
||||
func TfInit0(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -init")
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -init")
|
||||
//err := utils.Command("cd " + Path + " && terraform init")
|
||||
if err != nil {
|
||||
fmt.Println("场景初始化失败,再次尝试!", err)
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -init")
|
||||
if err2 != nil {
|
||||
fmt.Println("场景初始化失败,请检查网络连接!", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 复制后的初始化
|
||||
func TfInit(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -init")
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -init")
|
||||
//err := utils.Command("cd " + Path + " && terraform init")
|
||||
if err != nil {
|
||||
fmt.Println("场景初始化失败,再次尝试!", err)
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -init")
|
||||
if err2 != nil {
|
||||
fmt.Println("场景初始化失败,请检查网络连接!", err)
|
||||
|
||||
// 无法初始化,删除 case 文件夹
|
||||
err = os.RemoveAll(Path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(3)
|
||||
}
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TfApply(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -start")
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -start")
|
||||
if err != nil {
|
||||
fmt.Println("场景创建失败!尝试重新创建!")
|
||||
|
||||
// 先关闭
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -stop")
|
||||
if err2 != nil {
|
||||
fmt.Println("场景销毁,等待重新创建!")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
// 重新创建
|
||||
err3 := utils.Command("cd " + Path + " && bash deploy.sh -start")
|
||||
if err3 != nil {
|
||||
fmt.Println("场景创建第二次失败!请手动排查问题")
|
||||
fmt.Println("path路径: ", Path)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TfStatus(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -status")
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -status")
|
||||
if err != nil {
|
||||
fmt.Println("场景状态查询失败!请手动排查问题")
|
||||
fmt.Println("path路径: ", Path)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
|
||||
func TfDestroy(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -stop")
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -stop")
|
||||
if err != nil {
|
||||
fmt.Println("场景销毁失败,第二次尝试!", err)
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -stop")
|
||||
if err2 != nil {
|
||||
fmt.Println("场景销毁失败,第三次尝试!", err)
|
||||
|
||||
// 第三次
|
||||
err3 := utils.Command("cd " + Path + " && bash deploy.sh -stop")
|
||||
if err3 != nil {
|
||||
fmt.Println("场景销毁多次重试失败!请手动排查问题")
|
||||
fmt.Println("path路径: ", Path)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func C2Apply(Path string) {
|
||||
|
||||
// 先开c2
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -step1")
|
||||
if err != nil {
|
||||
fmt.Println("场景创建失败,自动销毁场景!")
|
||||
RedcLog("场景创建失败,自动销毁场景!")
|
||||
C2Destroy(Path, strconv.Itoa(Node), Domain)
|
||||
// 成功销毁场景后,删除 case 文件夹
|
||||
err = os.RemoveAll(Path)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
// 开rg
|
||||
if Node != 0 {
|
||||
err = utils.Command("cd " + Path + " && bash deploy.sh -step2 " + strconv.Itoa(Node) + " " + Domain)
|
||||
if err != nil {
|
||||
fmt.Println("场景创建失败,自动销毁场景!")
|
||||
RedcLog("场景创建失败,自动销毁场景!")
|
||||
C2Destroy(Path, strconv.Itoa(Node), Domain)
|
||||
// 成功销毁场景后,删除 case 文件夹
|
||||
err = os.RemoveAll(Path)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
|
||||
// 获得本地几个变量
|
||||
c2_ip := utils.Command2("cd " + Path + " && cd c2-ecs" + "&& terraform output -json ecs_ip | jq '.' -r")
|
||||
c2_pass := utils.Command2("cd " + Path + " && cd c2-ecs" + "&& terraform output -json ecs_password | jq '.' -r")
|
||||
|
||||
cs_port := "8080"
|
||||
cs_pass := "q!w@e#raa1dd2ff3gg4"
|
||||
cs_domain := Domain
|
||||
ssh_ip := c2_ip + ":22"
|
||||
|
||||
// 去掉该死的换行符
|
||||
ssh_ip = strings.Replace(ssh_ip, "\n", "", -1)
|
||||
c2_pass = strings.Replace(c2_pass, "\n", "", -1)
|
||||
c2_ip = strings.Replace(c2_ip, "\n", "", -1)
|
||||
|
||||
time.Sleep(time.Second * 60)
|
||||
|
||||
// ssh上去起teamserver
|
||||
if Node != 0 {
|
||||
ipsum := utils.Command2("cd " + Path + "&& cd zone-node && cat ipsum.txt")
|
||||
ecs_main_ip := utils.Command2("cd " + Path + "&& cd zone-node && cat ecs_main_ip.txt")
|
||||
ipsum = strings.Replace(ipsum, "\n", "", -1)
|
||||
ecs_main_ip = strings.Replace(ecs_main_ip, "\n", "", -1)
|
||||
cscommand := "setsid ./teamserver -new " + cs_port + " " + c2_ip + " " + cs_pass + " " + cs_domain + " " + ipsum + " " + ecs_main_ip + " > /dev/null 2>&1 &"
|
||||
fmt.Println("cscommand: ", cscommand)
|
||||
err = utils.Gotossh("root", c2_pass, ssh_ip, cscommand)
|
||||
if err != nil {
|
||||
mod2.PrintOnError(err, "ssh 过程出现报错!自动销毁场景")
|
||||
RedcLog("ssh 过程出现报错!自动销毁场景")
|
||||
C2Destroy(Path, strconv.Itoa(Node), Domain)
|
||||
// 成功销毁场景后,删除 case 文件夹
|
||||
err = os.RemoveAll(Path)
|
||||
os.Exit(3)
|
||||
}
|
||||
} else {
|
||||
cscommand := "setsid ./teamserver -new " + cs_port + " " + c2_ip + " " + cs_pass + " " + cs_domain + " > /dev/null 2>&1 &"
|
||||
fmt.Println("cscommand: ", cscommand)
|
||||
err = utils.Gotossh("root", c2_pass, ssh_ip, cscommand)
|
||||
if err != nil {
|
||||
mod2.PrintOnError(err, "ssh 过程出现报错!自动销毁场景")
|
||||
RedcLog("ssh 过程出现报错!自动销毁场景")
|
||||
C2Destroy(Path, strconv.Itoa(Node), Domain)
|
||||
// 成功销毁场景后,删除 case 文件夹
|
||||
err = os.RemoveAll(Path)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("ssh结束!")
|
||||
|
||||
err = utils.Command("cd " + Path + " && bash deploy.sh -status")
|
||||
|
||||
if err != nil {
|
||||
mod2.PrintOnError(err, "场景创建失败")
|
||||
RedcLog("场景创建失败")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func C2Change(Path string) {
|
||||
|
||||
// 重开rg
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -step3 " + strconv.Itoa(Node) + " " + Domain)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -step3 " + strconv.Itoa(Node) + " " + Domain)
|
||||
if err != nil {
|
||||
mod2.PrintOnError(err, "场景更改失败")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
// 获得本地几个变量
|
||||
c2_ip := utils.Command2("cd " + Path + " && cd c2-ecs" + "&& terraform output -json ecs_ip | jq '.' -r")
|
||||
c2_pass := utils.Command2("cd " + Path + " && cd c2-ecs" + "&& terraform output -json ecs_password | jq '.' -r")
|
||||
ipsum := utils.Command2("cd " + Path + "&& cd zone-node && cat ipsum.txt")
|
||||
ecs_main_ip := utils.Command2("cd " + Path + "&& cd zone-node && cat ecs_main_ip.txt")
|
||||
|
||||
cs_port := "8080"
|
||||
cs_pass := "q!w@e#raa1dd2ff3gg4"
|
||||
cs_domain := "360.com"
|
||||
ssh_ip := c2_ip + ":22"
|
||||
|
||||
// 去掉该死的换行符
|
||||
ssh_ip = strings.Replace(ssh_ip, "\n", "", -1)
|
||||
c2_pass = strings.Replace(c2_pass, "\n", "", -1)
|
||||
c2_ip = strings.Replace(c2_ip, "\n", "", -1)
|
||||
ipsum = strings.Replace(ipsum, "\n", "", -1)
|
||||
ecs_main_ip = strings.Replace(ecs_main_ip, "\n", "", -1)
|
||||
cscommand := "setsid ./teamserver -changelistener1 " + cs_port + " " + c2_ip + " " + cs_pass + " " + cs_domain + " " + ipsum + " " + ecs_main_ip + " > /dev/null 2>&1 &"
|
||||
|
||||
// ssh上去起teamserver
|
||||
utils.Gotossh("root", c2_pass, ssh_ip, cscommand)
|
||||
|
||||
}
|
||||
|
||||
func C2Destroy(Path string, Command1 string, Domain string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -stop " + Command1 + " " + Domain)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1 + " " + Domain)
|
||||
if err != nil {
|
||||
fmt.Println("场景销毁失败,第一次尝试!", err)
|
||||
RedcLog("场景销毁失败,第一次尝试!")
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1 + " " + Domain)
|
||||
if err2 != nil {
|
||||
fmt.Println("场景销毁失败,第二次尝试!", err)
|
||||
RedcLog("场景销毁失败,第二次尝试!")
|
||||
|
||||
// 第三次
|
||||
err3 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1 + " " + Domain)
|
||||
if err3 != nil {
|
||||
fmt.Println("场景销毁失败!")
|
||||
RedcLog("场景销毁失败")
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func AwsProxyApply(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -start " + strconv.Itoa(Node))
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -start " + strconv.Itoa(Node))
|
||||
if err != nil {
|
||||
fmt.Println("场景创建失败!")
|
||||
RedcLog("场景创建失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func AwsProxyDestroy(Path string, Command1 string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -stop " + Command1)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1)
|
||||
if err != nil {
|
||||
fmt.Println("场景销毁失败,第一次尝试!", err)
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1)
|
||||
if err2 != nil {
|
||||
fmt.Println("场景销毁失败,第二次尝试!", err)
|
||||
|
||||
// 第三次
|
||||
err3 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1)
|
||||
if err3 != nil {
|
||||
fmt.Println("场景销毁失败!")
|
||||
RedcLog("场景销毁失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func DDOSApply(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -start " + strconv.Itoa(Node) + " " + Durl + " " + strconv.Itoa(Dnum) + " " + strconv.Itoa(Dtime) + " " + Dmode)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -start " + strconv.Itoa(Node) + " " + Durl + " " + strconv.Itoa(Dnum) + " " + strconv.Itoa(Dtime) + " " + Dmode)
|
||||
if err != nil {
|
||||
fmt.Println("场景创建失败!")
|
||||
RedcLog("场景创建失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func DDOSDestroy(Path string, Command1 string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -stop " + Command1 + "1 1 1 1")
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1 + "1 1 1 1")
|
||||
if err != nil {
|
||||
fmt.Println("场景销毁失败,第一次尝试!", err)
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1 + "1 1 1 1")
|
||||
if err2 != nil {
|
||||
fmt.Println("场景销毁失败,第二次尝试!", err)
|
||||
|
||||
// 第三次
|
||||
err3 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1 + "1 1 1 1")
|
||||
if err3 != nil {
|
||||
fmt.Println("场景销毁失败!")
|
||||
RedcLog("场景销毁失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func AliyunProxyApply(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -start " + strconv.Itoa(Node))
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -start " + strconv.Itoa(Node))
|
||||
if err != nil {
|
||||
fmt.Println("场景创建失败!")
|
||||
RedcLog("场景创建失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func AliyunProxyChange(Path string) {
|
||||
|
||||
// 重开proxy
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -change " + strconv.Itoa(Node))
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -change " + strconv.Itoa(Node))
|
||||
if err != nil {
|
||||
fmt.Println("场景更改失败!")
|
||||
RedcLog("场景更改失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func AliyunProxyDestroy(Path string, Command1 string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -stop " + Command1)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1)
|
||||
if err != nil {
|
||||
fmt.Println("场景销毁失败,第一次尝试!", err)
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1)
|
||||
if err2 != nil {
|
||||
fmt.Println("场景销毁失败,第二次尝试!", err)
|
||||
|
||||
// 第三次
|
||||
err3 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Command1)
|
||||
if err3 != nil {
|
||||
fmt.Println("场景销毁失败!")
|
||||
RedcLog("场景销毁失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func DnslogApply(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -start " + Domain)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -start " + Domain)
|
||||
if err != nil {
|
||||
fmt.Println("场景创建失败!")
|
||||
RedcLog("场景创建失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func DnslogDestroy(Path string, Domain string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -stop " + Domain)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Domain)
|
||||
if err != nil {
|
||||
fmt.Println("场景销毁失败,第一次尝试!", err)
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Domain)
|
||||
if err2 != nil {
|
||||
fmt.Println("场景销毁失败,第二次尝试!", err)
|
||||
|
||||
// 第三次
|
||||
err3 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Domain)
|
||||
if err3 != nil {
|
||||
fmt.Println("场景销毁失败!")
|
||||
RedcLog("场景销毁失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Base64Apply(Path string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -start " + Base64Command)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -start " + Base64Command)
|
||||
if err != nil {
|
||||
fmt.Println("场景创建失败!")
|
||||
RedcLog("场景创建失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Base64Destroy(Path string, Base64Command string) {
|
||||
|
||||
fmt.Println("cd " + Path + " && bash deploy.sh -stop " + Base64Command)
|
||||
err := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Base64Command)
|
||||
if err != nil {
|
||||
fmt.Println("场景销毁失败,第一次尝试!", err)
|
||||
|
||||
// 如果初始化失败就再次尝试一次
|
||||
err2 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Base64Command)
|
||||
if err2 != nil {
|
||||
fmt.Println("场景销毁失败,第二次尝试!", err)
|
||||
|
||||
// 第三次
|
||||
err3 := utils.Command("cd " + Path + " && bash deploy.sh -stop " + Base64Command)
|
||||
if err3 != nil {
|
||||
fmt.Println("场景销毁失败!")
|
||||
RedcLog("场景销毁失败!")
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
21
mod2/error.go
Normal file
21
mod2/error.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package mod2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// PrintOnError 错误处理
|
||||
func PrintOnError(err error, msg string) {
|
||||
if err != nil {
|
||||
fmt.Println("%s: %s", msg, err)
|
||||
}
|
||||
}
|
||||
|
||||
// ExitOnError 退出
|
||||
func ExitOnError(err error, msg string) {
|
||||
if err != nil {
|
||||
fmt.Println("%s: %s", msg, err)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
5
push.sh
Normal file
5
push.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
# git config user.email mazhaojie@snowtech.com.cn
|
||||
# git config user.email
|
||||
git add -A
|
||||
git commit -m "[feat]:update [修改说明]:update"
|
||||
git push
|
||||
129
utils/exec.go
Normal file
129
utils/exec.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// 参考 https://www.cnblogs.com/we8fans/p/14031109.html
|
||||
|
||||
type Charset string
|
||||
|
||||
const (
|
||||
UTF8 = Charset("UTF-8")
|
||||
GB18030 = Charset("GB18030")
|
||||
)
|
||||
|
||||
func Command(cmd string) error {
|
||||
c := exec.Command("bash", "-c", cmd) // mac or linux
|
||||
stdout, err := c.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
reader := bufio.NewReader(stdout)
|
||||
for {
|
||||
readString, err := reader.ReadString('\n')
|
||||
if err != nil || err == io.EOF {
|
||||
return
|
||||
}
|
||||
byte2String := ConvertByte2String([]byte(readString), "GB18030")
|
||||
fmt.Print(byte2String)
|
||||
}
|
||||
}()
|
||||
err = c.Run()
|
||||
wg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
func CommandUTF(cmd string) error {
|
||||
c := exec.Command("bash", "-c", cmd) // mac or linux
|
||||
stdout, err := c.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
reader := bufio.NewReader(stdout)
|
||||
for {
|
||||
readString, err := reader.ReadString('\n')
|
||||
if err != nil || err == io.EOF {
|
||||
return
|
||||
}
|
||||
byte2String := ConvertByte2String([]byte(readString), "UTF-8")
|
||||
fmt.Print(byte2String)
|
||||
}
|
||||
}()
|
||||
err = c.Run()
|
||||
wg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
func NoPrintCommand(cmd string) error {
|
||||
c := exec.Command("bash", "-c", cmd) // mac or linux
|
||||
stdout, err := c.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
reader := bufio.NewReader(stdout)
|
||||
for {
|
||||
readString, err := reader.ReadString('\n')
|
||||
if err != nil || err == io.EOF {
|
||||
return
|
||||
}
|
||||
byte2String := ConvertByte2String([]byte(readString), "GB18030")
|
||||
f, err := os.OpenFile("log.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
f.Close()
|
||||
}()
|
||||
|
||||
log.SetOutput(f)
|
||||
log.Println(byte2String)
|
||||
}
|
||||
}()
|
||||
err = c.Run()
|
||||
wg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
func ConvertByte2String(byte []byte, charset Charset) string {
|
||||
var str string
|
||||
switch charset {
|
||||
case GB18030:
|
||||
var decodeBytes, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(byte)
|
||||
str = string(decodeBytes)
|
||||
case UTF8:
|
||||
fallthrough
|
||||
default:
|
||||
str = string(byte)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func Command2(cmd string) string {
|
||||
c2 := exec.Command("bash", "-c", cmd)
|
||||
out, err := c2.Output()
|
||||
if err != nil {
|
||||
fmt.Printf(cmd + " 运行失败")
|
||||
os.Exit(3)
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
161
utils/io.go
Normal file
161
utils/io.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed redc-templates
|
||||
var local embed.FS
|
||||
var dirs []string
|
||||
|
||||
// File copies a single file from src to dst
|
||||
func File(src, dst string) error {
|
||||
var err error
|
||||
var srcfd *os.File
|
||||
var dstfd *os.File
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
if srcfd, err = os.Open(src); err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcfd.Close()
|
||||
|
||||
if dstfd, err = os.Create(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstfd.Close()
|
||||
|
||||
if _, err = io.Copy(dstfd, srcfd); err != nil {
|
||||
return err
|
||||
}
|
||||
if srcinfo, err = os.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chmod(dst, srcinfo.Mode())
|
||||
}
|
||||
|
||||
// Dir copies a whole directory recursively
|
||||
func Dir(src string, dst string) error {
|
||||
var err error
|
||||
var fds []os.FileInfo
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
if srcinfo, err = os.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fds, err = ioutil.ReadDir(src); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, fd := range fds {
|
||||
srcfp := path.Join(src, fd.Name())
|
||||
dstfp := path.Join(dst, fd.Name())
|
||||
|
||||
if fd.IsDir() {
|
||||
if err = Dir(srcfp, dstfp); err != nil {
|
||||
//fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
if err = File(srcfp, dstfp); err != nil {
|
||||
//fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetFilesAndDirs(dirPth string) (files []string, dirs []string) {
|
||||
dir, err := ioutil.ReadDir(dirPth)
|
||||
if err != nil {
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
PthSep := string(os.PathSeparator)
|
||||
//suffix = strings.ToUpper(suffix) //忽略后缀匹配的大小写
|
||||
|
||||
for _, fi := range dir {
|
||||
if fi.IsDir() { // 目录, 递归遍历
|
||||
dirs = append(dirs, dirPth+PthSep+fi.Name())
|
||||
GetFilesAndDirs(dirPth + PthSep + fi.Name())
|
||||
} else {
|
||||
// 过滤指定格式
|
||||
ok := strings.HasSuffix(fi.Name(), ".go")
|
||||
if ok {
|
||||
files = append(files, dirPth+PthSep+fi.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files, dirs
|
||||
}
|
||||
|
||||
// ReleaseDir 释放文件夹
|
||||
func ReleaseDir(path string) {
|
||||
dirs, _ := local.ReadDir(path)
|
||||
for _, entry := range dirs {
|
||||
if entry.IsDir() {
|
||||
//_ = utils.Dir(path+"/"+entry.Name(), path+"/"+entry.Name())
|
||||
err := os.MkdirAll(path+"/"+entry.Name(), os.ModePerm)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
ReleaseDir(path + "/" + entry.Name())
|
||||
} else {
|
||||
//_ = utils.File(path+"/"+entry.Name(), path+"/"+entry.Name())
|
||||
out, _ := os.Create(path + "/" + entry.Name())
|
||||
in, _ := local.Open(path + "/" + entry.Name())
|
||||
_, err := io.Copy(out, in)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
in.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ChechDirMain 递归
|
||||
func ChechDirMain(dirPth string) []string {
|
||||
ChechDirSub(dirPth)
|
||||
return dirs
|
||||
}
|
||||
|
||||
func ChechDirSub(dirPth string) {
|
||||
dir, err := ioutil.ReadDir(dirPth)
|
||||
if err != nil {
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
PthSep := string(os.PathSeparator)
|
||||
|
||||
for _, fi := range dir {
|
||||
if fi.IsDir() { // 目录, 递归遍历
|
||||
dirs = append(dirs, dirPth+PthSep+fi.Name())
|
||||
ChechDirSub(dirPth + "/" + fi.Name())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func CheckFileName(path string, key string) bool {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err == nil {
|
||||
for _, fileInfo := range files {
|
||||
if strings.Contains(fileInfo.Name(), key) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
45
utils/redc-templates/ecs/deploy.sh
Normal file
45
utils/redc-templates/ecs/deploy.sh
Normal file
@@ -0,0 +1,45 @@
|
||||
init(){
|
||||
|
||||
terraform init
|
||||
|
||||
}
|
||||
|
||||
start_ecs(){
|
||||
|
||||
terraform apply -auto-approve
|
||||
|
||||
}
|
||||
|
||||
stop_ecs(){
|
||||
|
||||
terraform destroy -auto-approve
|
||||
|
||||
}
|
||||
|
||||
status_ecs(){
|
||||
|
||||
terraform output
|
||||
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
-init)
|
||||
init
|
||||
;;
|
||||
-start)
|
||||
start_ecs
|
||||
;;
|
||||
-stop)
|
||||
stop_ecs
|
||||
;;
|
||||
-status)
|
||||
status_ecs
|
||||
;;
|
||||
-h)
|
||||
echo -e "\033[1;34m使用 -init 初始化\033[0m"
|
||||
echo -e "\033[1;34m使用 -start 启动\033[0m"
|
||||
echo -e "\033[1;34m使用 -stop 关闭\033[0m"
|
||||
echo -e "\033[1;34m使用 -status 查询状态\033[0m"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
91
utils/redc-templates/ecs/main.tf
Normal file
91
utils/redc-templates/ecs/main.tf
Normal file
@@ -0,0 +1,91 @@
|
||||
provider "random" {}
|
||||
|
||||
resource "random_password" "password" {
|
||||
length = 10
|
||||
special = true
|
||||
override_special = "_%@"
|
||||
}
|
||||
|
||||
resource "alicloud_instance" "instance" {
|
||||
security_groups = alicloud_security_group.group.*.id
|
||||
instance_type = "ecs.c6.large"
|
||||
image_id = "debian_12_2_x64_20G_alibase_20231012.vhd"
|
||||
instance_name = "aliyun_bj_ecs"
|
||||
vswitch_id = alicloud_vswitch.vswitch.id
|
||||
system_disk_size = 20
|
||||
internet_max_bandwidth_out = 100
|
||||
password = random_password.password.result
|
||||
user_data = <<EOF
|
||||
#!/bin/bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates
|
||||
sudo apt-get install -y curl
|
||||
sudo apt-get -y install wget
|
||||
sudo apt-get install -y lrzsz
|
||||
sudo apt-get install -y tmux
|
||||
sudo apt-get install -y unzip
|
||||
sudo echo "set-option -g history-limit 20000" >> ~/.tmux.conf
|
||||
sudo echo "set -g mouse on" >> ~/.tmux.conf
|
||||
|
||||
sudo wget http://update.aegis.aliyun.com/download/uninstall.sh
|
||||
sudo chmod +x uninstall.sh
|
||||
sudo ./uninstall.sh
|
||||
sudo wget http://update.aegis.aliyun.com/download/quartz_uninstall.sh
|
||||
sudo chmod +x quartz_uninstall.sh
|
||||
sudo ./quartz_uninstall.sh
|
||||
sudo pkill aliyun-service
|
||||
sudo rm -fr /etc/init.d/agentwatch /usr/sbin/aliyun-service
|
||||
sudo rm -rf /usr/local/aegis*
|
||||
sudo rm /usr/sbin/aliyun-service
|
||||
sudo rm /lib/systemd/system/aliyun.service
|
||||
sudo systemctl stop aliyun.service
|
||||
|
||||
sudo wget -O simplehttpserver_0.0.5_linux_amd64.tar.gz 'https://pub-4cbde83fd01f4fe98e2672c3b1f14315.r2.dev/file-server/simplehttpserver_0.0.5_linux_amd64.tar.gz'
|
||||
sudo tar -zxvf simplehttpserver_0.0.5_linux_amd64.tar.gz
|
||||
sudo mv --force simplehttpserver /usr/local/bin/simplehttpserver
|
||||
sudo chmod +x /usr/local/bin/simplehttpserver
|
||||
|
||||
sudo curl -o f8x https://f8x.io/ && mv --force f8x /usr/local/bin/f8x && chmod +x /usr/local/bin/f8x
|
||||
|
||||
sudo apt-get install -y python3-pip
|
||||
sudo pip3 install trzsz --break-system-packages
|
||||
|
||||
EOF
|
||||
|
||||
}
|
||||
|
||||
resource "alicloud_security_group" "group" {
|
||||
name = "test_security_group"
|
||||
vpc_id = alicloud_vpc.vpc.id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "allow_all_tcp" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
nic_type = "intranet"
|
||||
policy = "accept"
|
||||
port_range = "1/65535"
|
||||
priority = 1
|
||||
security_group_id = alicloud_security_group.group.id
|
||||
cidr_ip = "0.0.0.0/0"
|
||||
depends_on = [
|
||||
alicloud_security_group.group
|
||||
]
|
||||
}
|
||||
|
||||
resource "alicloud_vswitch" "vswitch" {
|
||||
vpc_id = alicloud_vpc.vpc.id
|
||||
cidr_block = "172.16.0.0/24"
|
||||
zone_id = data.alicloud_zones.default.zones[0].id
|
||||
vswitch_name = "aliyun_zjk_vswitch"
|
||||
|
||||
}
|
||||
resource "alicloud_vpc" "vpc" {
|
||||
vpc_name = "test_vpc"
|
||||
cidr_block = "172.16.0.0/16"
|
||||
}
|
||||
|
||||
data "alicloud_zones" "default" {
|
||||
available_resource_creation = "VSwitch"
|
||||
available_instance_type = "ecs.c6.large"
|
||||
}
|
||||
8
utils/redc-templates/ecs/outputs.tf
Normal file
8
utils/redc-templates/ecs/outputs.tf
Normal file
@@ -0,0 +1,8 @@
|
||||
output "ecs_ip" {
|
||||
value = "${alicloud_instance.instance.public_ip}"
|
||||
description = "ip"
|
||||
}
|
||||
output "ecs_password" {
|
||||
value = nonsensitive(random_password.password.result)
|
||||
description = "vps password."
|
||||
}
|
||||
13
utils/redc-templates/ecs/versions.tf
Normal file
13
utils/redc-templates/ecs/versions.tf
Normal file
@@ -0,0 +1,13 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
alicloud = {
|
||||
source = "aliyun/alicloud"
|
||||
version = "1.190.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "alicloud" {
|
||||
profile = "cloud-tool"
|
||||
region = "cn-beijing"
|
||||
}
|
||||
45
utils/ssh.go
Normal file
45
utils/ssh.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"red-cloud/mod2"
|
||||
)
|
||||
|
||||
func Gotossh(username string, password string, addr string, cmd string) error {
|
||||
//fmt.Println("ssh上去起teamserver!")
|
||||
config := &ssh.ClientConfig{
|
||||
User: username,
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.Password(password),
|
||||
},
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
client, err := ssh.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
mod2.PrintOnError(err, "Failed to dial")
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// 开启一个session,用于执行一个命令
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
mod2.PrintOnError(err, "Failed to create session")
|
||||
return err
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
// 执行命令,并将执行的结果写到 b 中
|
||||
var b bytes.Buffer
|
||||
session.Stdout = &b
|
||||
|
||||
// 也可以使用 session.CombinedOutput() 整合输出
|
||||
if err := session.Run(cmd); err != nil {
|
||||
mod2.PrintOnError(err, "Failed to run")
|
||||
return err
|
||||
}
|
||||
fmt.Println(b.String())
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user