main.go 8.2 KB

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