main.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package main
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "fmt"
  6. "math/rand"
  7. "net/http"
  8. "net/url"
  9. "os"
  10. "os/exec"
  11. "os/signal"
  12. "strings"
  13. "syscall"
  14. "time"
  15. "gopkg.in/ini.v1"
  16. )
  17. var configFile = "./oci-help.ini"
  18. var cfg *ini.File
  19. var defSec *ini.Section
  20. var tg_token string
  21. var tg_chatId string
  22. var name string
  23. type Result struct {
  24. Status json.Number `json:"status"`
  25. Message string `json:"message"`
  26. Data Data `json:"data"`
  27. }
  28. type Data struct {
  29. InstanceName string `json:"display-name"`
  30. Shape string `json:"shape"`
  31. }
  32. type Node struct {
  33. Name string `ini:"name"`
  34. ADId string `ini:"ad_id"`
  35. ImageId string `ini:"image_id"`
  36. SubnetId string `ini:"subnet_id"`
  37. KeyPub string `ini:"key_pub"`
  38. Tenancy string `ini:"tenancy_id"`
  39. Shape string `ini:"shape"`
  40. CPU string `ini:"cpu_num"`
  41. RAM string `ini:"ram_num"`
  42. HD string `ini:"hd_num"`
  43. MinTime int `ini:"min_time"`
  44. MaxTime int `ini:"max_time"`
  45. }
  46. func main() {
  47. _, Error := os.Stat(configFile)
  48. if os.IsNotExist(Error) {
  49. os.Create(configFile)
  50. }
  51. cfg, _ = ini.Load(configFile)
  52. defSec = cfg.Section("")
  53. tg_token = defSec.Key("token").Value()
  54. tg_chatId = defSec.Key("chat_id").Value()
  55. rand.Seed(time.Now().UnixNano())
  56. setCloseHandler()
  57. mainMenu()
  58. }
  59. func mainMenu() {
  60. cmdClear()
  61. fmt.Printf("\n\033[1;32;40m%s\033[0m\n\n", "欢迎使用甲骨文实例抢购脚本")
  62. fmt.Printf("\033[1;36;40m%s\033[0m %s\n", "1.", "历史抢购实例任务")
  63. fmt.Printf("\033[1;36;40m%s\033[0m %s\n", "2.", "新建抢购实例任务")
  64. fmt.Printf("\033[1;36;40m%s\033[0m %s\n", "3.", "Telegram Bot 消息提醒")
  65. fmt.Println("")
  66. fmt.Print("请选择[1-3]: ")
  67. var num int
  68. fmt.Scanln(&num)
  69. switch num {
  70. case 1:
  71. loadNode()
  72. case 2:
  73. addNode()
  74. case 3:
  75. setTelegramBot()
  76. }
  77. }
  78. func loadNode() {
  79. cmdClear()
  80. sections := cfg.Sections()
  81. fmt.Printf("\n\033[1;32;40m%s\033[0m\n\n", "历史抢购实例任务")
  82. for i := 1; i < len(sections); i++ {
  83. fmt.Printf("\033[1;36;40m%d.\033[0m %s\n", i, sections[i].Name())
  84. }
  85. fmt.Printf("\n\033[1;36;40m%d.\033[0m %s\n", 0, "返回主菜单")
  86. var num int
  87. fmt.Print("\n请输入序号, 开始抢购实例: ")
  88. fmt.Scanln(&num)
  89. if num <= 0 || num >= len(sections) {
  90. mainMenu()
  91. return
  92. }
  93. section := sections[num]
  94. node := new(Node)
  95. err := section.MapTo(node)
  96. if err != nil {
  97. fmt.Println("MapTo failed: ", err)
  98. return
  99. }
  100. launchInstance(node)
  101. }
  102. func addNode() {
  103. cmdClear()
  104. var (
  105. name string
  106. ad_id string
  107. image_id string
  108. subnet_id string
  109. key_pub string
  110. tenancy_id string
  111. shape string
  112. cpu_num string
  113. ram_num string
  114. hd_num string
  115. min_time string
  116. max_time string
  117. )
  118. fmt.Printf("\n\033[1;32;40m%s\033[0m\n\n", "新建抢购实例任务, 请按要求输入以下参数")
  119. fmt.Print("请随便输入一个名称(不能有空格): ")
  120. fmt.Scanln(&name)
  121. fmt.Print("请输入[availabilityDomain|availability_domain]: ")
  122. fmt.Scanln(&ad_id)
  123. fmt.Print("请输入[imageId|source_id]: ")
  124. fmt.Scanln(&image_id)
  125. fmt.Print("请输入[subnetId|subnet_id]: ")
  126. fmt.Scanln(&subnet_id)
  127. fmt.Print("请输入[ssh_authorized_keys]: ")
  128. reader := bufio.NewReader(os.Stdin)
  129. key_pub, _ = reader.ReadString('\n')
  130. key_pub = strings.TrimSuffix(key_pub, "\n")
  131. fmt.Print("请输入[compartmentId|compartment_id]: ")
  132. fmt.Scanln(&tenancy_id)
  133. fmt.Print("请输入[shape]: ")
  134. fmt.Scanln(&shape)
  135. fmt.Print("请输入CPU个数: ")
  136. fmt.Scanln(&cpu_num)
  137. fmt.Print("请输入内存大小(GB): ")
  138. fmt.Scanln(&ram_num)
  139. fmt.Print("请输入引导卷大小(GB): ")
  140. fmt.Scanln(&hd_num)
  141. fmt.Print("请输入最小间隔时间(秒): ")
  142. fmt.Scanln(&min_time)
  143. fmt.Print("请输入最大间隔时间(秒): ")
  144. fmt.Scanln(&max_time)
  145. section := cfg.Section(name)
  146. section.Key("name").SetValue(name)
  147. section.NewKey("ad_id", ad_id)
  148. section.NewKey("image_id", image_id)
  149. section.NewKey("subnet_id", subnet_id)
  150. section.NewKey("key_pub", key_pub)
  151. section.NewKey("tenancy_id", tenancy_id)
  152. section.NewKey("shape", shape)
  153. section.NewKey("cpu_num", cpu_num)
  154. section.NewKey("ram_num", ram_num)
  155. section.NewKey("hd_num", hd_num)
  156. section.Key("min_time").SetValue(min_time)
  157. section.Key("max_time").SetValue(max_time)
  158. cfg.SaveTo(configFile)
  159. node := new(Node)
  160. err := section.MapTo(node)
  161. if err != nil {
  162. fmt.Println("MapTo failed: ", err)
  163. return
  164. }
  165. launchInstance(node)
  166. }
  167. func setTelegramBot() {
  168. cmdClear()
  169. fmt.Printf("\n\033[1;32;40m%s\033[0m\n\n", "Telegram Bot 消息提醒配置")
  170. fmt.Println("Telegram Bot Token:", tg_token)
  171. fmt.Println("Telegram User ID:", tg_chatId)
  172. fmt.Printf("\n\033[1;36;40m%s\033[0m %s\n", "1.", "设置token和用户id")
  173. fmt.Printf("\n\033[1;36;40m%s\033[0m %s\n", "0.", "返回主菜单")
  174. fmt.Print("\n请选择[0-1]: ")
  175. var num int
  176. fmt.Scanln(&num)
  177. switch num {
  178. case 1:
  179. fmt.Print("请输入 Telegram Bot Token: ")
  180. fmt.Scanln(&tg_token)
  181. fmt.Print("请输入 Telegram User ID: ")
  182. fmt.Scanln(&tg_chatId)
  183. defSec.Key("token").SetValue(tg_token)
  184. defSec.Key("chat_id").SetValue(tg_chatId)
  185. cfg.SaveTo(configFile)
  186. fmt.Println("设置成功")
  187. mainMenu()
  188. default:
  189. mainMenu()
  190. }
  191. }
  192. func sendMessage(name, text string) {
  193. tg_url := "https://api.telegram.org/bot" + tg_token + "/sendMessage"
  194. urlValues := url.Values{
  195. "parse_mode": {"Markdown"},
  196. "chat_id": {tg_chatId},
  197. "text": {"*甲骨文通知*\n名称: " + name + "\n" + "内容: " + text},
  198. }
  199. cli := http.Client{Timeout: 10 * time.Second}
  200. _, err := cli.PostForm(tg_url, urlValues)
  201. if err != nil {
  202. printYellow("Telegram 消息提醒发送失败" + err.Error())
  203. }
  204. }
  205. func launchInstance(node *Node) {
  206. name = node.Name
  207. text := "开始抢购实例"
  208. printGreen(text)
  209. sendMessage(node.Name, text)
  210. cmd := "oci"
  211. args := []string{
  212. "compute", "instance", "launch",
  213. "--availability-domain", node.ADId,
  214. "--image-id", node.ImageId,
  215. "--subnet-id", node.SubnetId,
  216. "--metadata", `{"ssh_authorized_keys": "` + node.KeyPub + `"}`,
  217. "--compartment-id", node.Tenancy,
  218. "--shape", node.Shape,
  219. "--shape-config", `{"ocpus":` + node.CPU + `,"memory_in_gbs":` + node.RAM + `}`,
  220. "--boot-volume-size-in-gbs", node.HD,
  221. "--assign-public-ip", "true",
  222. "--is-pv-encryption-in-transit-enabled", "true",
  223. }
  224. for {
  225. printYellow("正在尝试新建实例......")
  226. out, err := exec.Command(cmd, args...).CombinedOutput()
  227. ret := string(out)
  228. // 防止 Ctrl + C 取消误报
  229. if Cancel {
  230. return
  231. }
  232. if err != nil && out == nil {
  233. text = "抢购失败, " + err.Error() + "\n" + ret
  234. printRed(text)
  235. sendMessage(node.Name, text)
  236. return
  237. }
  238. pos := strings.Index(ret, "{")
  239. if pos != -1 {
  240. ret = ret[pos:]
  241. }
  242. var result Result
  243. err = json.Unmarshal([]byte(ret), &result)
  244. if err != nil {
  245. text = "抢购失败, " + "\n" + ret
  246. printRed(text)
  247. sendMessage(node.Name, text)
  248. return
  249. }
  250. switch result.Status {
  251. case "500", "429":
  252. printNone(result.Message)
  253. default:
  254. if result.Data != (Data{}) {
  255. text = "抢购成功, 实例名称: [" + result.Data.InstanceName + "]"
  256. printGreen(text)
  257. sendMessage(node.Name, text)
  258. return
  259. }
  260. text = "抢购失败, " + result.Message
  261. printRed(text)
  262. sendMessage(node.Name, text)
  263. return
  264. }
  265. random := random(node.MinTime, node.MaxTime)
  266. time.Sleep(time.Duration(random) * time.Second)
  267. }
  268. }
  269. func random(min, max int) int {
  270. if min == 0 || max == 0 {
  271. return 1
  272. }
  273. if min >= max {
  274. return max
  275. }
  276. return rand.Intn(max-min) + min
  277. }
  278. var Cancel bool = false
  279. func setCloseHandler() {
  280. c := make(chan os.Signal)
  281. signal.Notify(c, os.Interrupt, syscall.SIGTERM)
  282. go func() {
  283. <-c
  284. Cancel = true
  285. fmt.Printf("\033[1;33;40m%s\033[0m\n", "已停止")
  286. if name != "" {
  287. sendMessage(name, "已停止")
  288. }
  289. os.Exit(0)
  290. }()
  291. }
  292. func cmdClear() {
  293. cmd := exec.Command("clear")
  294. cmd.Stdout = os.Stdout
  295. cmd.Run()
  296. }
  297. func printRed(str string) {
  298. fmt.Print(time.Now().Format("[2006-01-02 15:04:05] "))
  299. fmt.Printf("\033[1;31;40m%s\033[0m\n", str)
  300. }
  301. func printGreen(str string) {
  302. fmt.Print(time.Now().Format("[2006-01-02 15:04:05] "))
  303. fmt.Printf("\033[1;32;40m%s\033[0m\n", str)
  304. }
  305. func printYellow(str string) {
  306. fmt.Print(time.Now().Format("[2006-01-02 15:04:05] "))
  307. fmt.Printf("\033[1;33;40m%s\033[0m\n", str)
  308. }
  309. func printNone(str string) {
  310. fmt.Print(time.Now().Format("[2006-01-02 15:04:05] "))
  311. fmt.Printf("%s\n", str)
  312. }