main.go 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367
  1. /*
  2. 甲骨文云API文档
  3. https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/
  4. 实例:
  5. https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/Instance/
  6. VCN:
  7. https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/Vcn/
  8. Subnet:
  9. https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/Subnet/
  10. VNIC:
  11. https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/Vnic/
  12. VnicAttachment:
  13. https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/VnicAttachment/
  14. 私有IP
  15. https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/PrivateIp/
  16. 公共IP
  17. https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/PublicIp/
  18. 获取可用性域
  19. https://docs.oracle.com/en-us/iaas/api/#/en/identity/20160918/AvailabilityDomain/ListAvailabilityDomains
  20. */
  21. package main
  22. import (
  23. "bytes"
  24. "context"
  25. "encoding/json"
  26. "errors"
  27. "flag"
  28. "fmt"
  29. "io"
  30. "io/ioutil"
  31. "math"
  32. "math/rand"
  33. "net/http"
  34. "net/url"
  35. "os"
  36. "strconv"
  37. "strings"
  38. "sync"
  39. "text/tabwriter"
  40. "time"
  41. "github.com/oracle/oci-go-sdk/v54/common"
  42. "github.com/oracle/oci-go-sdk/v54/core"
  43. "github.com/oracle/oci-go-sdk/v54/example/helpers"
  44. "github.com/oracle/oci-go-sdk/v54/identity"
  45. "gopkg.in/ini.v1"
  46. )
  47. const (
  48. defConfigFilePath = "./oci-help.ini"
  49. IPsFilePrefix = "IPs"
  50. )
  51. var (
  52. configFilePath string
  53. provider common.ConfigurationProvider
  54. computeClient core.ComputeClient
  55. networkClient core.VirtualNetworkClient
  56. storageClient core.BlockstorageClient
  57. identityClient identity.IdentityClient
  58. ctx context.Context
  59. oracleSections []*ini.Section
  60. oracleSection *ini.Section
  61. oracleSectionName string
  62. oracle Oracle
  63. instanceBaseSection *ini.Section
  64. instance Instance
  65. proxy string
  66. token string
  67. chat_id string
  68. sendMessageUrl string
  69. editMessageUrl string
  70. EACH bool
  71. availabilityDomains []identity.AvailabilityDomain
  72. )
  73. type Oracle struct {
  74. User string `ini:"user"`
  75. Fingerprint string `ini:"fingerprint"`
  76. Tenancy string `ini:"tenancy"`
  77. Region string `ini:"region"`
  78. Key_file string `ini:"key_file"`
  79. Key_password string `ini:"key_password"`
  80. }
  81. type Instance struct {
  82. AvailabilityDomain string `ini:"availabilityDomain"`
  83. SSH_Public_Key string `ini:"ssh_authorized_key"`
  84. VcnDisplayName string `ini:"vcnDisplayName"`
  85. SubnetDisplayName string `ini:"subnetDisplayName"`
  86. Shape string `ini:"shape"`
  87. OperatingSystem string `ini:"OperatingSystem"`
  88. OperatingSystemVersion string `ini:"OperatingSystemVersion"`
  89. InstanceDisplayName string `ini:"instanceDisplayName"`
  90. Ocpus float32 `ini:"cpus"`
  91. MemoryInGBs float32 `ini:"memoryInGBs"`
  92. BootVolumeSizeInGBs int64 `ini:"bootVolumeSizeInGBs"`
  93. Sum int32 `ini:"sum"`
  94. Each int32 `ini:"each"`
  95. Retry int32 `ini:"retry"`
  96. CloudInit string `ini:"cloud-init"`
  97. MinTime int32 `ini:"minTime"`
  98. MaxTime int32 `ini:"maxTime"`
  99. }
  100. type Message struct {
  101. OK bool `json:"ok"`
  102. Result `json:"result"`
  103. ErrorCode int `json:"error_code"`
  104. Description string `json:"description"`
  105. }
  106. type Result struct {
  107. MessageId int `json:"message_id"`
  108. }
  109. func main() {
  110. flag.StringVar(&configFilePath, "config", defConfigFilePath, "配置文件路径")
  111. flag.StringVar(&configFilePath, "c", defConfigFilePath, "配置文件路径")
  112. flag.Parse()
  113. cfg, err := ini.Load(configFilePath)
  114. helpers.FatalIfError(err)
  115. defSec := cfg.Section(ini.DefaultSection)
  116. proxy = defSec.Key("proxy").Value()
  117. token = defSec.Key("token").Value()
  118. chat_id = defSec.Key("chat_id").Value()
  119. if defSec.HasKey("EACH") {
  120. EACH, _ = defSec.Key("EACH").Bool()
  121. } else {
  122. EACH = true
  123. }
  124. sendMessageUrl = "https://api.telegram.org/bot" + token + "/sendMessage"
  125. editMessageUrl = "https://api.telegram.org/bot" + token + "/editMessageText"
  126. rand.Seed(time.Now().UnixNano())
  127. sections := cfg.Sections()
  128. oracleSections = []*ini.Section{}
  129. for _, sec := range sections {
  130. if len(sec.ParentKeys()) == 0 {
  131. user := sec.Key("user").Value()
  132. fingerprint := sec.Key("fingerprint").Value()
  133. tenancy := sec.Key("tenancy").Value()
  134. region := sec.Key("region").Value()
  135. key_file := sec.Key("key_file").Value()
  136. if user != "" && fingerprint != "" && tenancy != "" && region != "" && key_file != "" {
  137. oracleSections = append(oracleSections, sec)
  138. }
  139. }
  140. }
  141. if len(oracleSections) == 0 {
  142. fmt.Printf("\033[1;31m未找到正确的配置信息, 请参考链接文档配置相关信息。链接: https://github.com/lemoex/oci-help\033[0m\n")
  143. return
  144. }
  145. instanceBaseSection = cfg.Section("INSTANCE")
  146. listOracleAccount()
  147. }
  148. func listOracleAccount() {
  149. if len(oracleSections) == 1 {
  150. oracleSection = oracleSections[0]
  151. } else {
  152. fmt.Printf("\n\033[1;32m%s\033[0m\n\n", "欢迎使用甲骨文实例管理工具")
  153. w := new(tabwriter.Writer)
  154. w.Init(os.Stdout, 4, 8, 1, '\t', 0)
  155. fmt.Fprintf(w, "%s\t%s\t\n", "序号", "账号")
  156. for i, section := range oracleSections {
  157. fmt.Fprintf(w, "%d\t%s\t\n", i+1, section.Name())
  158. }
  159. w.Flush()
  160. fmt.Printf("\n")
  161. var input string
  162. var index int
  163. for {
  164. fmt.Print("请输入账号对应的序号进入相关操作: ")
  165. _, err := fmt.Scanln(&input)
  166. if err != nil {
  167. return
  168. }
  169. if strings.EqualFold(input, "oci") {
  170. multiBatchLaunchInstances()
  171. listOracleAccount()
  172. return
  173. } else if strings.EqualFold(input, "ip") {
  174. multiBatchListInstancesIp()
  175. listOracleAccount()
  176. return
  177. }
  178. index, _ = strconv.Atoi(input)
  179. if 0 < index && index <= len(oracleSections) {
  180. break
  181. } else {
  182. index = 0
  183. input = ""
  184. fmt.Printf("\033[1;31m错误! 请输入正确的序号\033[0m\n")
  185. }
  186. }
  187. oracleSection = oracleSections[index-1]
  188. }
  189. var err error
  190. ctx = context.Background()
  191. err = initVar(oracleSection)
  192. if err != nil {
  193. return
  194. }
  195. // 获取可用性域
  196. fmt.Println("正在获取可用性域...")
  197. availabilityDomains, err = ListAvailabilityDomains()
  198. if err != nil {
  199. printlnErr("获取可用性域失败", err.Error())
  200. return
  201. }
  202. showMainMenu()
  203. }
  204. func initVar(oracleSec *ini.Section) (err error) {
  205. oracleSectionName = oracleSec.Name()
  206. oracle = Oracle{}
  207. err = oracleSec.MapTo(&oracle)
  208. if err != nil {
  209. printlnErr("解析账号相关参数失败", err.Error())
  210. return
  211. }
  212. provider, err = getProvider(oracle)
  213. if err != nil {
  214. printlnErr("获取 Provider 失败", err.Error())
  215. return
  216. }
  217. computeClient, err = core.NewComputeClientWithConfigurationProvider(provider)
  218. if err != nil {
  219. printlnErr("创建 ComputeClient 失败", err.Error())
  220. return
  221. }
  222. setProxyOrNot(&computeClient.BaseClient)
  223. networkClient, err = core.NewVirtualNetworkClientWithConfigurationProvider(provider)
  224. if err != nil {
  225. printlnErr("创建 VirtualNetworkClient 失败", err.Error())
  226. return
  227. }
  228. setProxyOrNot(&networkClient.BaseClient)
  229. storageClient, err = core.NewBlockstorageClientWithConfigurationProvider(provider)
  230. if err != nil {
  231. printlnErr("创建 BlockstorageClient 失败", err.Error())
  232. return
  233. }
  234. setProxyOrNot(&storageClient.BaseClient)
  235. identityClient, err = identity.NewIdentityClientWithConfigurationProvider(provider)
  236. if err != nil {
  237. printlnErr("创建 IdentityClient 失败", err.Error())
  238. return
  239. }
  240. setProxyOrNot(&identityClient.BaseClient)
  241. return
  242. }
  243. func showMainMenu() {
  244. fmt.Printf("\n\033[1;32m欢迎使用甲骨文实例管理工具\033[0m \n(当前账号: %s)\n\n", oracleSection.Name())
  245. fmt.Printf("\033[1;36m%s\033[0m %s\n", "1.", "查看实例")
  246. fmt.Printf("\033[1;36m%s\033[0m %s\n", "2.", "创建实例")
  247. fmt.Printf("\033[1;36m%s\033[0m %s\n", "3.", "管理引导卷")
  248. fmt.Print("\n请输入序号进入相关操作: ")
  249. var input string
  250. var num int
  251. fmt.Scanln(&input)
  252. if strings.EqualFold(input, "oci") {
  253. batchLaunchInstances(oracleSection)
  254. showMainMenu()
  255. return
  256. } else if strings.EqualFold(input, "ip") {
  257. batchListInstancesIp(oracleSection)
  258. showMainMenu()
  259. return
  260. }
  261. num, _ = strconv.Atoi(input)
  262. switch num {
  263. case 1:
  264. listInstances()
  265. case 2:
  266. listLaunchInstanceTemplates()
  267. case 3:
  268. listBootVolumes()
  269. default:
  270. if len(oracleSections) > 1 {
  271. listOracleAccount()
  272. }
  273. }
  274. }
  275. func listInstances() {
  276. fmt.Println("正在获取实例数据...")
  277. instances, err := ListInstances(ctx, computeClient)
  278. if err != nil {
  279. printlnErr("获取失败, 回车返回上一级菜单.", err.Error())
  280. fmt.Scanln()
  281. showMainMenu()
  282. return
  283. }
  284. if len(instances) == 0 {
  285. fmt.Printf("\033[1;32m实例为空, 回车返回上一级菜单.\033[0m")
  286. fmt.Scanln()
  287. showMainMenu()
  288. return
  289. }
  290. fmt.Printf("\n\033[1;32m实例信息\033[0m \n(当前账号: %s)\n\n", oracleSection.Name())
  291. w := new(tabwriter.Writer)
  292. w.Init(os.Stdout, 4, 8, 1, '\t', 0)
  293. fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", "序号", "名称", "状态  ", "配置")
  294. //fmt.Printf("%-5s %-28s %-18s %-20s\n", "序号", "名称", "公共IP", "配置")
  295. for i, ins := range instances {
  296. // 获取实例公共IP
  297. /*
  298. var strIps string
  299. ips, err := getInstancePublicIps(ctx, computeClient, networkClient, ins.Id)
  300. if err != nil {
  301. strIps = err.Error()
  302. } else {
  303. strIps = strings.Join(ips, ",")
  304. }
  305. */
  306. //fmt.Printf("%-7d %-30s %-20s %-20s\n", i+1, *ins.DisplayName, strIps, *ins.Shape)
  307. fmt.Fprintf(w, "%d\t%s\t%s\t%s\t\n", i+1, *ins.DisplayName, getInstanceState(ins.LifecycleState), *ins.Shape)
  308. }
  309. w.Flush()
  310. fmt.Println("--------------------")
  311. fmt.Printf("\n\033[1;32ma: %s b: %s c: %s d: %s\033[0m\n", "启动全部", "停止全部", "重启全部", "终止全部")
  312. var input string
  313. var index int
  314. for {
  315. fmt.Print("请输入序号查看实例详细信息: ")
  316. _, err := fmt.Scanln(&input)
  317. if err != nil {
  318. showMainMenu()
  319. return
  320. }
  321. switch input {
  322. case "a":
  323. fmt.Printf("确定启动全部实例?(输入 y 并回车): ")
  324. var input string
  325. fmt.Scanln(&input)
  326. if strings.EqualFold(input, "y") {
  327. for _, ins := range instances {
  328. _, err := instanceAction(ins.Id, core.InstanceActionActionStart)
  329. if err != nil {
  330. fmt.Printf("\033[1;31m实例 %s 启动失败.\033[0m %s\n", *ins.DisplayName, err.Error())
  331. } else {
  332. fmt.Printf("\033[1;32m实例 %s 启动成功.\033[0m\n", *ins.DisplayName)
  333. }
  334. }
  335. } else {
  336. continue
  337. }
  338. time.Sleep(1 * time.Second)
  339. listInstances()
  340. return
  341. case "b":
  342. fmt.Printf("确定停止全部实例?(输入 y 并回车): ")
  343. var input string
  344. fmt.Scanln(&input)
  345. if strings.EqualFold(input, "y") {
  346. for _, ins := range instances {
  347. _, err := instanceAction(ins.Id, core.InstanceActionActionSoftstop)
  348. if err != nil {
  349. fmt.Printf("\033[1;31m实例 %s 停止失败.\033[0m %s\n", *ins.DisplayName, err.Error())
  350. } else {
  351. fmt.Printf("\033[1;32m实例 %s 停止成功.\033[0m\n", *ins.DisplayName)
  352. }
  353. }
  354. } else {
  355. continue
  356. }
  357. time.Sleep(1 * time.Second)
  358. listInstances()
  359. return
  360. case "c":
  361. fmt.Printf("确定重启全部实例?(输入 y 并回车): ")
  362. var input string
  363. fmt.Scanln(&input)
  364. if strings.EqualFold(input, "y") {
  365. for _, ins := range instances {
  366. _, err := instanceAction(ins.Id, core.InstanceActionActionSoftreset)
  367. if err != nil {
  368. fmt.Printf("\033[1;31m实例 %s 重启失败.\033[0m %s\n", *ins.DisplayName, err.Error())
  369. } else {
  370. fmt.Printf("\033[1;32m实例 %s 重启成功.\033[0m\n", *ins.DisplayName)
  371. }
  372. }
  373. } else {
  374. continue
  375. }
  376. time.Sleep(1 * time.Second)
  377. listInstances()
  378. return
  379. case "d":
  380. fmt.Printf("确定终止全部实例?(输入 y 并回车): ")
  381. var input string
  382. fmt.Scanln(&input)
  383. if strings.EqualFold(input, "y") {
  384. for _, ins := range instances {
  385. err := terminateInstance(ins.Id)
  386. if err != nil {
  387. fmt.Printf("\033[1;31m实例 %s 终止失败.\033[0m %s\n", *ins.DisplayName, err.Error())
  388. } else {
  389. fmt.Printf("\033[1;32m实例 %s 终止成功.\033[0m\n", *ins.DisplayName)
  390. }
  391. }
  392. } else {
  393. continue
  394. }
  395. time.Sleep(1 * time.Second)
  396. listInstances()
  397. return
  398. }
  399. index, _ = strconv.Atoi(input)
  400. if 0 < index && index <= len(instances) {
  401. break
  402. } else {
  403. input = ""
  404. index = 0
  405. fmt.Printf("\033[1;31m错误! 请输入正确的序号\033[0m\n")
  406. }
  407. }
  408. instanceDetails(instances[index-1].Id)
  409. }
  410. func instanceDetails(instanceId *string) {
  411. for {
  412. fmt.Println("正在获取实例详细信息...")
  413. instance, err := getInstance(instanceId)
  414. if err != nil {
  415. fmt.Printf("\033[1;31m获取实例详细信息失败, 回车返回上一级菜单.\033[0m")
  416. fmt.Scanln()
  417. listInstances()
  418. return
  419. }
  420. vnics, err := getInstanceVnics(instanceId)
  421. if err != nil {
  422. fmt.Printf("\033[1;31m获取实例VNIC失败, 回车返回上一级菜单.\033[0m")
  423. fmt.Scanln()
  424. listInstances()
  425. return
  426. }
  427. var publicIps = make([]string, 0)
  428. var strPublicIps string
  429. if err != nil {
  430. strPublicIps = err.Error()
  431. } else {
  432. for _, vnic := range vnics {
  433. if vnic.PublicIp != nil {
  434. publicIps = append(publicIps, *vnic.PublicIp)
  435. }
  436. }
  437. strPublicIps = strings.Join(publicIps, ",")
  438. }
  439. fmt.Printf("\n\033[1;32m实例详细信息\033[0m \n(当前账号: %s)\n\n", oracleSection.Name())
  440. fmt.Println("--------------------")
  441. fmt.Printf("名称: %s\n", *instance.DisplayName)
  442. fmt.Printf("状态: %s\n", getInstanceState(instance.LifecycleState))
  443. fmt.Printf("公共IP: %s\n", strPublicIps)
  444. fmt.Printf("可用性域: %s\n", *instance.AvailabilityDomain)
  445. fmt.Printf("配置: %s\n", *instance.Shape)
  446. fmt.Printf("OCPU计数: %g\n", *instance.ShapeConfig.Ocpus)
  447. fmt.Printf("网络带宽(Gbps): %g\n", *instance.ShapeConfig.NetworkingBandwidthInGbps)
  448. fmt.Printf("内存(GB): %g\n", *instance.ShapeConfig.MemoryInGBs)
  449. fmt.Println("--------------------")
  450. fmt.Printf("\n\033[1;32m1: %s 2: %s 3: %s 4: %s 5: %s\033[0m\n", "启动", "停止", "重启", "终止", "更换公共IP")
  451. var input string
  452. var num int
  453. fmt.Print("\n请输入需要执行操作的序号: ")
  454. fmt.Scanln(&input)
  455. num, _ = strconv.Atoi(input)
  456. switch num {
  457. case 1:
  458. _, err := instanceAction(instance.Id, core.InstanceActionActionStart)
  459. if err != nil {
  460. fmt.Printf("\033[1;31m启动实例失败.\033[0m %s\n", err.Error())
  461. } else {
  462. fmt.Printf("\033[1;32m正在启动实例, 请稍后查看实例状态\033[0m\n")
  463. }
  464. time.Sleep(3 * time.Second)
  465. case 2:
  466. _, err := instanceAction(instance.Id, core.InstanceActionActionSoftstop)
  467. if err != nil {
  468. fmt.Printf("\033[1;31m停止实例失败.\033[0m %s\n", err.Error())
  469. } else {
  470. fmt.Printf("\033[1;32m正在停止实例, 请稍后查看实例状态\033[0m\n")
  471. }
  472. time.Sleep(3 * time.Second)
  473. case 3:
  474. _, err := instanceAction(instance.Id, core.InstanceActionActionSoftreset)
  475. if err != nil {
  476. fmt.Printf("\033[1;31m重启实例失败.\033[0m %s\n", err.Error())
  477. } else {
  478. fmt.Printf("\033[1;32m正在重启实例, 请稍后查看实例状态\033[0m\n")
  479. }
  480. time.Sleep(3 * time.Second)
  481. case 4:
  482. fmt.Printf("确定终止实例?(输入 y 并回车): ")
  483. var input string
  484. fmt.Scanln(&input)
  485. if strings.EqualFold(input, "y") {
  486. err := terminateInstance(instance.Id)
  487. if err != nil {
  488. fmt.Printf("\033[1;31m终止实例失败.\033[0m %s\n", err.Error())
  489. } else {
  490. fmt.Printf("\033[1;32m正在终止实例, 请稍后查看实例状态\033[0m\n")
  491. }
  492. time.Sleep(3 * time.Second)
  493. }
  494. case 5:
  495. if len(vnics) == 0 {
  496. fmt.Printf("\033[1;31m实例已终止或获取实例VNIC失败,请稍后重试.\033[0m\n")
  497. break
  498. }
  499. fmt.Printf("将删除当前公共IP并创建一个新的公共IP。确定更换实例公共IP?(输入 y 并回车): ")
  500. var input string
  501. fmt.Scanln(&input)
  502. if strings.EqualFold(input, "y") {
  503. publicIp, err := changePublicIp(vnics)
  504. if err != nil {
  505. fmt.Printf("\033[1;31m更换实例公共IP失败.\033[0m %s\n", err.Error())
  506. } else {
  507. fmt.Printf("\033[1;32m更换实例公共IP成功, 实例公共IP: \033[0m%s\n", *publicIp.IpAddress)
  508. }
  509. time.Sleep(3 * time.Second)
  510. }
  511. default:
  512. listInstances()
  513. return
  514. }
  515. }
  516. }
  517. func listBootVolumes() {
  518. var bootVolumes []core.BootVolume
  519. var wg sync.WaitGroup
  520. for _, ad := range availabilityDomains {
  521. wg.Add(1)
  522. go func(adName *string) {
  523. defer wg.Done()
  524. volumes, err := getBootVolumes(adName)
  525. if err != nil {
  526. printlnErr("获取引导卷失败", err.Error())
  527. } else {
  528. bootVolumes = append(bootVolumes, volumes...)
  529. }
  530. }(ad.Name)
  531. }
  532. wg.Wait()
  533. fmt.Printf("\n\033[1;32m引导卷\033[0m \n(当前账号: %s)\n\n", oracleSection.Name())
  534. w := new(tabwriter.Writer)
  535. w.Init(os.Stdout, 4, 8, 1, '\t', 0)
  536. fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", "序号", "名称", "状态  ", "大小(GB)")
  537. for i, volume := range bootVolumes {
  538. fmt.Fprintf(w, "%d\t%s\t%s\t%d\t\n", i+1, *volume.DisplayName, getBootVolumeState(volume.LifecycleState), *volume.SizeInGBs)
  539. }
  540. w.Flush()
  541. fmt.Printf("\n")
  542. var input string
  543. var index int
  544. for {
  545. fmt.Print("请输入序号查看引导卷详细信息: ")
  546. _, err := fmt.Scanln(&input)
  547. if err != nil {
  548. showMainMenu()
  549. return
  550. }
  551. index, _ = strconv.Atoi(input)
  552. if 0 < index && index <= len(bootVolumes) {
  553. break
  554. } else {
  555. input = ""
  556. index = 0
  557. fmt.Printf("\033[1;31m错误! 请输入正确的序号\033[0m\n")
  558. }
  559. }
  560. bootvolumeDetails(bootVolumes[index-1].Id)
  561. }
  562. func bootvolumeDetails(bootVolumeId *string) {
  563. for {
  564. fmt.Println("正在获取引导卷详细信息...")
  565. bootVolume, err := getBootVolume(bootVolumeId)
  566. if err != nil {
  567. fmt.Printf("\033[1;31m获取引导卷详细信息失败, 回车返回上一级菜单.\033[0m")
  568. fmt.Scanln()
  569. listBootVolumes()
  570. return
  571. }
  572. attachments, err := listBootVolumeAttachments(bootVolume.AvailabilityDomain, bootVolume.CompartmentId, bootVolume.Id)
  573. attachIns := make([]string, 0)
  574. if err != nil {
  575. attachIns = append(attachIns, err.Error())
  576. } else {
  577. for _, attachment := range attachments {
  578. ins, err := getInstance(attachment.InstanceId)
  579. if err != nil {
  580. attachIns = append(attachIns, err.Error())
  581. } else {
  582. attachIns = append(attachIns, *ins.DisplayName)
  583. }
  584. }
  585. }
  586. var performance string
  587. switch *bootVolume.VpusPerGB {
  588. case 10:
  589. performance = fmt.Sprintf("均衡 (VPU:%d)", *bootVolume.VpusPerGB)
  590. case 20:
  591. performance = fmt.Sprintf("性能较高 (VPU:%d)", *bootVolume.VpusPerGB)
  592. default:
  593. performance = fmt.Sprintf("UHP (VPU:%d)", *bootVolume.VpusPerGB)
  594. }
  595. fmt.Printf("\n\033[1;32m引导卷详细信息\033[0m \n(当前账号: %s)\n\n", oracleSection.Name())
  596. fmt.Println("--------------------")
  597. fmt.Printf("名称: %s\n", *bootVolume.DisplayName)
  598. fmt.Printf("状态: %s\n", getBootVolumeState(bootVolume.LifecycleState))
  599. fmt.Printf("可用性域: %s\n", *bootVolume.AvailabilityDomain)
  600. fmt.Printf("大小(GB): %d\n", *bootVolume.SizeInGBs)
  601. fmt.Printf("性能: %s\n", performance)
  602. fmt.Printf("附加的实例: %s\n", strings.Join(attachIns, ","))
  603. fmt.Println("--------------------")
  604. fmt.Printf("\n\033[1;32m1: %s 2: %s 3: %s 4: %s\033[0m\n", "修改性能", "修改大小", "分离引导卷", "终止引导卷")
  605. var input string
  606. var num int
  607. fmt.Print("\n请输入需要执行操作的序号: ")
  608. fmt.Scanln(&input)
  609. num, _ = strconv.Atoi(input)
  610. switch num {
  611. case 1:
  612. fmt.Printf("修改引导卷性能, 请输入 (1: 均衡; 2: 性能较高): ")
  613. var input string
  614. fmt.Scanln(&input)
  615. if input == "1" {
  616. _, err := updateBootVolume(bootVolume.Id, nil, common.Int64(10))
  617. if err != nil {
  618. fmt.Printf("\033[1;31m修改引导卷性能失败.\033[0m %s\n", err.Error())
  619. } else {
  620. fmt.Printf("\033[1;32m修改引导卷性能成功, 请稍后查看引导卷状态\033[0m\n")
  621. }
  622. } else if input == "2" {
  623. _, err := updateBootVolume(bootVolume.Id, nil, common.Int64(20))
  624. if err != nil {
  625. fmt.Printf("\033[1;31m修改引导卷性能失败.\033[0m %s\n", err.Error())
  626. } else {
  627. fmt.Printf("\033[1;32m修改引导卷性能成功, 请稍后查看引导卷信息\033[0m\n")
  628. }
  629. } else {
  630. fmt.Printf("\033[1;31m输入错误.\033[0m\n")
  631. }
  632. time.Sleep(1 * time.Second)
  633. case 2:
  634. fmt.Printf("修改引导卷大小, 请输入 (例如修改为50GB, 输入50): ")
  635. var input string
  636. var sizeInGBs int64
  637. fmt.Scanln(&input)
  638. sizeInGBs, _ = strconv.ParseInt(input, 10, 64)
  639. if sizeInGBs > 0 {
  640. _, err := updateBootVolume(bootVolume.Id, &sizeInGBs, nil)
  641. if err != nil {
  642. fmt.Printf("\033[1;31m修改引导卷大小失败.\033[0m %s\n", err.Error())
  643. } else {
  644. fmt.Printf("\033[1;32m修改引导卷大小成功, 请稍后查看引导卷信息\033[0m\n")
  645. }
  646. } else {
  647. fmt.Printf("\033[1;31m输入错误.\033[0m\n")
  648. }
  649. time.Sleep(1 * time.Second)
  650. case 3:
  651. fmt.Printf("确定分离引导卷?(输入 y 并回车): ")
  652. var input string
  653. fmt.Scanln(&input)
  654. if strings.EqualFold(input, "y") {
  655. for _, attachment := range attachments {
  656. _, err := detachBootVolume(attachment.Id)
  657. if err != nil {
  658. fmt.Printf("\033[1;31m分离引导卷失败.\033[0m %s\n", err.Error())
  659. } else {
  660. fmt.Printf("\033[1;32m分离引导卷成功, 请稍后查看引导卷信息\033[0m\n")
  661. }
  662. }
  663. }
  664. time.Sleep(1 * time.Second)
  665. case 4:
  666. fmt.Printf("确定终止引导卷?(输入 y 并回车): ")
  667. var input string
  668. fmt.Scanln(&input)
  669. if strings.EqualFold(input, "y") {
  670. _, err := deleteBootVolume(bootVolume.Id)
  671. if err != nil {
  672. fmt.Printf("\033[1;31m终止引导卷失败.\033[0m %s\n", err.Error())
  673. } else {
  674. fmt.Printf("\033[1;32m终止引导卷成功, 请稍后查看引导卷信息\033[0m\n")
  675. }
  676. }
  677. time.Sleep(1 * time.Second)
  678. default:
  679. listBootVolumes()
  680. return
  681. }
  682. }
  683. }
  684. func listLaunchInstanceTemplates() {
  685. var instanceSections []*ini.Section
  686. instanceSections = append(instanceSections, instanceBaseSection.ChildSections()...)
  687. instanceSections = append(instanceSections, oracleSection.ChildSections()...)
  688. if len(instanceSections) == 0 {
  689. fmt.Printf("\033[1;31m未找到实例模版, 回车返回上一级菜单.\033[0m")
  690. fmt.Scanln()
  691. showMainMenu()
  692. return
  693. }
  694. for {
  695. fmt.Printf("\n\033[1;32m选择对应的实例模版开始创建实例\033[0m \n(当前账号: %s)\n\n", oracleSectionName)
  696. w := new(tabwriter.Writer)
  697. w.Init(os.Stdout, 4, 8, 1, '\t', 0)
  698. fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", "序号", "配置", "CPU个数", "内存(GB)")
  699. for i, instanceSec := range instanceSections {
  700. cpu := instanceSec.Key("cpus").Value()
  701. if cpu == "" {
  702. cpu = "-"
  703. }
  704. memory := instanceSec.Key("memoryInGBs").Value()
  705. if memory == "" {
  706. memory = "-"
  707. }
  708. fmt.Fprintf(w, "%d\t%s\t%s\t%s\t\n", i+1, instanceSec.Key("shape").Value(), cpu, memory)
  709. }
  710. w.Flush()
  711. fmt.Printf("\n")
  712. var input string
  713. var index int
  714. for {
  715. fmt.Print("请输入需要创建的实例的序号: ")
  716. _, err := fmt.Scanln(&input)
  717. if err != nil {
  718. showMainMenu()
  719. return
  720. }
  721. index, _ = strconv.Atoi(input)
  722. if 0 < index && index <= len(instanceSections) {
  723. break
  724. } else {
  725. input = ""
  726. index = 0
  727. fmt.Printf("\033[1;31m错误! 请输入正确的序号\033[0m\n")
  728. }
  729. }
  730. instanceSection := instanceSections[index-1]
  731. instance = Instance{}
  732. err := instanceSection.MapTo(&instance)
  733. if err != nil {
  734. printlnErr("解析实例模版参数失败", err.Error())
  735. continue
  736. }
  737. LaunchInstances(availabilityDomains)
  738. }
  739. }
  740. func multiBatchLaunchInstances() {
  741. for _, sec := range oracleSections {
  742. var err error
  743. err = initVar(sec)
  744. if err != nil {
  745. continue
  746. }
  747. // 获取可用性域
  748. availabilityDomains, err = ListAvailabilityDomains()
  749. if err != nil {
  750. printlnErr("获取可用性域失败", err.Error())
  751. continue
  752. }
  753. batchLaunchInstances(sec)
  754. }
  755. }
  756. func batchLaunchInstances(oracleSec *ini.Section) {
  757. var instanceSections []*ini.Section
  758. instanceSections = append(instanceSections, instanceBaseSection.ChildSections()...)
  759. instanceSections = append(instanceSections, oracleSec.ChildSections()...)
  760. if len(instanceSections) == 0 {
  761. return
  762. }
  763. printf("\033[1;36m[%s] 开始创建\033[0m\n", oracleSectionName)
  764. var SUM, NUM int32 = 0, 0
  765. sendMessage(fmt.Sprintf("[%s]", oracleSectionName), "开始创建")
  766. for _, instanceSec := range instanceSections {
  767. instance = Instance{}
  768. err := instanceSec.MapTo(&instance)
  769. if err != nil {
  770. printlnErr("解析实例模版参数失败", err.Error())
  771. continue
  772. }
  773. sum, num := LaunchInstances(availabilityDomains)
  774. SUM = SUM + sum
  775. NUM = NUM + num
  776. }
  777. printf("\033[1;36m[%s] 结束创建。创建实例总数: %d, 成功 %d , 失败 %d\033[0m\n", oracleSectionName, SUM, NUM, SUM-NUM)
  778. text := fmt.Sprintf("结束创建。创建实例总数: %d, 成功 %d , 失败 %d", SUM, NUM, SUM-NUM)
  779. sendMessage(fmt.Sprintf("[%s]", oracleSectionName), text)
  780. }
  781. func multiBatchListInstancesIp() {
  782. IPsFilePath := IPsFilePrefix + "-" + time.Now().Format("2006-01-02-150405.txt")
  783. _, err := os.Stat(IPsFilePath)
  784. if err != nil && os.IsNotExist(err) {
  785. os.Create(IPsFilePath)
  786. }
  787. fmt.Printf("正在导出实例公共IP地址...\n")
  788. for _, sec := range oracleSections {
  789. err := initVar(sec)
  790. if err != nil {
  791. continue
  792. }
  793. ListInstancesIPs(IPsFilePath, sec.Name())
  794. }
  795. fmt.Printf("导出实例公共IP地址完成,请查看文件 %s\n", IPsFilePath)
  796. }
  797. func batchListInstancesIp(sec *ini.Section) {
  798. IPsFilePath := IPsFilePrefix + "-" + time.Now().Format("2006-01-02-150405.txt")
  799. _, err := os.Stat(IPsFilePath)
  800. if err != nil && os.IsNotExist(err) {
  801. os.Create(IPsFilePath)
  802. }
  803. fmt.Printf("正在导出实例公共IP地址...\n")
  804. ListInstancesIPs(IPsFilePath, sec.Name())
  805. fmt.Printf("导出实例IP地址完成,请查看文件 %s\n", IPsFilePath)
  806. }
  807. func ListInstancesIPs(filePath string, sectionName string) {
  808. vnicAttachments, err := ListVnicAttachments(ctx, computeClient, nil)
  809. if err != nil {
  810. fmt.Printf("ListVnicAttachments Error: %s\n", err.Error())
  811. return
  812. }
  813. file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
  814. if err != nil {
  815. fmt.Printf("打开文件失败, Error: %s\n", err.Error())
  816. return
  817. }
  818. _, err = io.WriteString(file, "["+sectionName+"]\n")
  819. if err != nil {
  820. fmt.Printf("%s\n", err.Error())
  821. }
  822. for _, vnicAttachment := range vnicAttachments {
  823. vnic, err := GetVnic(ctx, networkClient, vnicAttachment.VnicId)
  824. if err != nil {
  825. fmt.Printf("IP地址获取失败, %s\n", err.Error())
  826. continue
  827. }
  828. fmt.Printf("[%s] 实例: %s, IP: %s\n", sectionName, *vnic.DisplayName, *vnic.PublicIp)
  829. _, err = io.WriteString(file, "实例: "+*vnic.DisplayName+", IP: "+*vnic.PublicIp+"\n")
  830. if err != nil {
  831. fmt.Printf("写入文件失败, Error: %s\n", err.Error())
  832. }
  833. }
  834. _, err = io.WriteString(file, "\n")
  835. if err != nil {
  836. fmt.Printf("%s\n", err.Error())
  837. }
  838. }
  839. // 返回值 sum: 创建实例总数; num: 创建成功的个数
  840. func LaunchInstances(ads []identity.AvailabilityDomain) (sum, num int32) {
  841. /* 创建实例的几种情况
  842. * 1. 设置了 availabilityDomain 参数,即在设置的可用性域中创建 sum 个实例。
  843. * 2. 没有设置 availabilityDomain 但是设置了 each 参数。即在获取的每个可用性域中创建 each 个实例,创建的实例总数 sum = each * adCount。
  844. * 3. 没有设置 availabilityDomain 且没有设置 each 参数,即在获取到的可用性域中创建的实例总数为 sum。
  845. */
  846. //可用性域数量
  847. var adCount int32 = int32(len(ads))
  848. adName := common.String(instance.AvailabilityDomain)
  849. each := instance.Each
  850. sum = instance.Sum
  851. // 没有设置可用性域并且没有设置each时,才有用。
  852. var usableAds = make([]identity.AvailabilityDomain, 0)
  853. //可用性域不固定,即没有提供 availabilityDomain 参数
  854. var AD_NOT_FIXED bool = false
  855. var EACH_AD = false
  856. if adName == nil || *adName == "" {
  857. AD_NOT_FIXED = true
  858. if each > 0 {
  859. EACH_AD = true
  860. sum = each * adCount
  861. } else {
  862. EACH_AD = false
  863. usableAds = ads
  864. }
  865. }
  866. name := instance.InstanceDisplayName
  867. if name == "" {
  868. name = time.Now().Format("instance-20060102-1504")
  869. }
  870. displayName := common.String(name)
  871. if sum > 1 {
  872. displayName = common.String(name + "-1")
  873. }
  874. // create the launch instance request
  875. request := core.LaunchInstanceRequest{}
  876. request.CompartmentId = common.String(oracle.Tenancy)
  877. request.DisplayName = displayName
  878. // Get a image.
  879. fmt.Println("正在获取系统镜像...")
  880. image, err := GetImage(ctx, computeClient)
  881. if err != nil {
  882. printlnErr("获取系统镜像失败", err.Error())
  883. return
  884. }
  885. fmt.Println("系统镜像:", *image.DisplayName)
  886. var shape core.Shape
  887. if strings.Contains(strings.ToLower(instance.Shape), "flex") && instance.Ocpus > 0 && instance.MemoryInGBs > 0 {
  888. shape.Shape = &instance.Shape
  889. shape.Ocpus = &instance.Ocpus
  890. shape.MemoryInGBs = &instance.MemoryInGBs
  891. } else {
  892. fmt.Println("正在获取Shape信息...")
  893. shape, err = getShape(image.Id, instance.Shape)
  894. if err != nil {
  895. printlnErr("获取Shape信息失败", err.Error())
  896. return
  897. }
  898. }
  899. request.Shape = shape.Shape
  900. if strings.Contains(strings.ToLower(*shape.Shape), "flex") {
  901. request.ShapeConfig = &core.LaunchInstanceShapeConfigDetails{
  902. Ocpus: shape.Ocpus,
  903. MemoryInGBs: shape.MemoryInGBs,
  904. }
  905. }
  906. // create a subnet or get the one already created
  907. fmt.Println("正在获取子网...")
  908. subnet, err := CreateOrGetNetworkInfrastructure(ctx, networkClient)
  909. if err != nil {
  910. printlnErr("获取子网失败", err.Error())
  911. return
  912. }
  913. fmt.Println("子网:", *subnet.DisplayName)
  914. request.CreateVnicDetails = &core.CreateVnicDetails{SubnetId: subnet.Id}
  915. sd := core.InstanceSourceViaImageDetails{}
  916. sd.ImageId = image.Id
  917. if instance.BootVolumeSizeInGBs > 0 {
  918. sd.BootVolumeSizeInGBs = common.Int64(instance.BootVolumeSizeInGBs)
  919. }
  920. request.SourceDetails = sd
  921. request.IsPvEncryptionInTransitEnabled = common.Bool(true)
  922. metaData := map[string]string{}
  923. metaData["ssh_authorized_keys"] = instance.SSH_Public_Key
  924. if instance.CloudInit != "" {
  925. metaData["user_data"] = instance.CloudInit
  926. }
  927. request.Metadata = metaData
  928. minTime := instance.MinTime
  929. maxTime := instance.MaxTime
  930. SKIP_RETRY_MAP := make(map[int32]bool)
  931. var usableAdsTemp = make([]identity.AvailabilityDomain, 0)
  932. retry := instance.Retry // 重试次数
  933. var failTimes int32 = 0 // 失败次数
  934. // 记录尝试创建实例的次数
  935. var runTimes int32 = 0
  936. var adIndex int32 = 0 // 当前可用性域下标
  937. var pos int32 = 0 // for 循环次数
  938. var SUCCESS = false // 创建是否成功
  939. var startTime = time.Now()
  940. var bootVolumeSize float64
  941. if instance.BootVolumeSizeInGBs > 0 {
  942. bootVolumeSize = float64(instance.BootVolumeSizeInGBs)
  943. } else {
  944. bootVolumeSize = math.Round(float64(*image.SizeInMBs) / float64(1024))
  945. }
  946. printf("\033[1;36m[%s] 开始创建 %s 实例, OCPU: %g 内存: %g 引导卷: %g \033[0m\n", oracleSectionName, *shape.Shape, *shape.Ocpus, *shape.MemoryInGBs, bootVolumeSize)
  947. if EACH {
  948. text := fmt.Sprintf("正在尝试创建第 %d 个实例...⏳\n区域: %s\n实例配置: %s\nOCPU计数: %g\n内存(GB): %g\n引导卷(GB): %g\n创建个数: %d", pos+1, oracle.Region, *shape.Shape, *shape.Ocpus, *shape.MemoryInGBs, bootVolumeSize, sum)
  949. _, err := sendMessage("", text)
  950. if err != nil {
  951. printlnErr("Telegram 消息提醒发送失败", err.Error())
  952. }
  953. }
  954. for pos < sum {
  955. if AD_NOT_FIXED {
  956. if EACH_AD {
  957. if pos%each == 0 && failTimes == 0 {
  958. adName = ads[adIndex].Name
  959. adIndex++
  960. }
  961. } else {
  962. if SUCCESS {
  963. adIndex = 0
  964. }
  965. if adIndex >= adCount {
  966. adIndex = 0
  967. }
  968. //adName = ads[adIndex].Name
  969. adName = usableAds[adIndex].Name
  970. adIndex++
  971. }
  972. }
  973. runTimes++
  974. printf("\033[1;36m[%s] 正在尝试创建第 %d 个实例, AD: %s\033[0m\n", oracleSectionName, pos+1, *adName)
  975. printf("\033[1;36m[%s] 当前尝试次数: %d \033[0m\n", oracleSectionName, runTimes)
  976. request.AvailabilityDomain = adName
  977. createResp, err := computeClient.LaunchInstance(ctx, request)
  978. if err == nil {
  979. // 创建实例成功
  980. SUCCESS = true
  981. num++ //成功个数+1
  982. duration := fmtDuration(time.Since(startTime))
  983. printf("\033[1;32m[%s] 第 %d 个实例抢到了🎉, 正在启动中请稍等...⌛️ \033[0m\n", oracleSectionName, pos+1)
  984. var msg Message
  985. var msgErr error
  986. var text string
  987. if EACH {
  988. text = fmt.Sprintf("第 %d 个实例抢到了🎉, 正在启动中请稍等...⌛️\n区域: %s\n实例名称: %s\n公共IP: 获取中...⏳\n可用性域:%s\n实例配置: %s\nOCPU计数: %g\n内存(GB): %g\n引导卷(GB): %g\n创建个数: %d\n尝试次数: %d\n耗时: %s", pos+1, oracle.Region, *createResp.Instance.DisplayName, *createResp.Instance.AvailabilityDomain, *shape.Shape, *shape.Ocpus, *shape.MemoryInGBs, bootVolumeSize, sum, runTimes, duration)
  989. msg, msgErr = sendMessage("", text)
  990. }
  991. // 获取实例公共IP
  992. var strIps string
  993. ips, err := getInstancePublicIps(createResp.Instance.Id)
  994. if err != nil {
  995. printf("\033[1;32m[%s] 第 %d 个实例抢到了🎉, 但是启动失败❌ 错误信息: \033[0m%s\n", oracleSectionName, pos+1, err.Error())
  996. text = fmt.Sprintf("第 %d 个实例抢到了🎉, 但是启动失败❌实例已被终止😔\n区域: %s\n实例名称: %s\n可用性域:%s\n实例配置: %s\nOCPU计数: %g\n内存(GB): %g\n引导卷(GB): %g\n创建个数: %d\n尝试次数: %d\n耗时: %s", pos+1, oracle.Region, *createResp.Instance.DisplayName, *createResp.Instance.AvailabilityDomain, *shape.Shape, *shape.Ocpus, *shape.MemoryInGBs, bootVolumeSize, sum, runTimes, duration)
  997. } else {
  998. strIps = strings.Join(ips, ",")
  999. printf("\033[1;32m[%s] 第 %d 个实例抢到了🎉, 启动成功✅. 实例名称: %s, 公共IP: %s\033[0m\n", oracleSectionName, pos+1, *createResp.Instance.DisplayName, strIps)
  1000. text = fmt.Sprintf("第 %d 个实例抢到了🎉, 启动成功✅\n区域: %s\n实例名称: %s\n公共IP: %s\n可用性域:%s\n实例配置: %s\nOCPU计数: %g\n内存(GB): %g\n引导卷(GB): %g\n创建个数: %d\n尝试次数: %d\n耗时: %s", pos+1, oracle.Region, *createResp.Instance.DisplayName, strIps, *createResp.Instance.AvailabilityDomain, *shape.Shape, *shape.Ocpus, *shape.MemoryInGBs, bootVolumeSize, sum, runTimes, duration)
  1001. }
  1002. if EACH {
  1003. if msgErr != nil {
  1004. sendMessage("", text)
  1005. } else {
  1006. editMessage(msg.MessageId, "", text)
  1007. }
  1008. }
  1009. sleepRandomSecond(minTime, maxTime)
  1010. displayName = common.String(fmt.Sprintf("%s-%d", name, pos+1))
  1011. request.DisplayName = displayName
  1012. } else {
  1013. // 创建实例失败
  1014. SUCCESS = false
  1015. // 错误信息
  1016. errInfo := err.Error()
  1017. // 是否跳过重试
  1018. SKIP_RETRY := false
  1019. //isRetryable := common.IsErrorRetryableByDefault(err)
  1020. //isNetErr := common.IsNetworkError(err)
  1021. servErr, isServErr := common.IsServiceError(err)
  1022. // API Errors: https://docs.cloud.oracle.com/Content/API/References/apierrors.htm
  1023. if isServErr && (400 <= servErr.GetHTTPStatusCode() && servErr.GetHTTPStatusCode() <= 405) ||
  1024. (servErr.GetHTTPStatusCode() == 409 && !strings.EqualFold(servErr.GetCode(), "IncorrectState")) ||
  1025. servErr.GetHTTPStatusCode() == 412 || servErr.GetHTTPStatusCode() == 413 || servErr.GetHTTPStatusCode() == 422 ||
  1026. servErr.GetHTTPStatusCode() == 431 || servErr.GetHTTPStatusCode() == 501 {
  1027. // 不可重试
  1028. if isServErr {
  1029. errInfo = servErr.GetMessage()
  1030. }
  1031. duration := fmtDuration(time.Since(startTime))
  1032. printf("\033[1;31m[%s] 第 %d 个实例创建失败了❌, 错误信息: \033[0m%s\n", oracleSectionName, pos+1, errInfo)
  1033. if EACH {
  1034. text := fmt.Sprintf("第 %d 个实例创建失败了❌\n错误信息: %s\n区域: %s\n可用性域: %s\n实例配置: %s\nOCPU计数: %g\n内存(GB): %g\n引导卷(GB): %g\n创建个数: %d\n尝试次数: %d\n耗时:%s", pos+1, errInfo, oracle.Region, *adName, *shape.Shape, *shape.Ocpus, *shape.MemoryInGBs, bootVolumeSize, sum, runTimes, duration)
  1035. sendMessage("", text)
  1036. }
  1037. SKIP_RETRY = true
  1038. if AD_NOT_FIXED && !EACH_AD {
  1039. SKIP_RETRY_MAP[adIndex-1] = true
  1040. }
  1041. } else {
  1042. // 可重试
  1043. if isServErr {
  1044. errInfo = servErr.GetMessage()
  1045. }
  1046. printf("\033[1;31m[%s] 创建失败, Error: \033[0m%s\n", oracleSectionName, errInfo)
  1047. SKIP_RETRY = false
  1048. if AD_NOT_FIXED && !EACH_AD {
  1049. SKIP_RETRY_MAP[adIndex-1] = false
  1050. }
  1051. }
  1052. sleepRandomSecond(minTime, maxTime)
  1053. if AD_NOT_FIXED {
  1054. if !EACH_AD {
  1055. if adIndex < adCount {
  1056. // 没有设置可用性域,且没有设置each。即在获取到的每个可用性域里尝试创建。当前使用的可用性域不是最后一个,继续尝试。
  1057. continue
  1058. } else {
  1059. // 当前使用的可用性域是最后一个,判断失败次数是否达到重试次数,未达到重试次数继续尝试。
  1060. failTimes++
  1061. for index, skip := range SKIP_RETRY_MAP {
  1062. if !skip {
  1063. usableAdsTemp = append(usableAdsTemp, usableAds[index])
  1064. }
  1065. }
  1066. // 重新设置 usableAds
  1067. usableAds = usableAdsTemp
  1068. adCount = int32(len(usableAds))
  1069. // 重置变量
  1070. usableAdsTemp = nil
  1071. for k := range SKIP_RETRY_MAP {
  1072. delete(SKIP_RETRY_MAP, k)
  1073. }
  1074. // 判断是否需要重试
  1075. if (retry < 0 || failTimes <= retry) && adCount > 0 {
  1076. continue
  1077. }
  1078. }
  1079. adIndex = 0
  1080. } else {
  1081. // 没有设置可用性域,且设置了each,即在每个域创建each个实例。判断失败次数继续尝试。
  1082. failTimes++
  1083. if (retry < 0 || failTimes <= retry) && !SKIP_RETRY {
  1084. continue
  1085. }
  1086. }
  1087. } else {
  1088. //设置了可用性域,判断是否需要重试
  1089. failTimes++
  1090. if (retry < 0 || failTimes <= retry) && !SKIP_RETRY {
  1091. continue
  1092. }
  1093. }
  1094. }
  1095. // 重置变量
  1096. usableAds = ads
  1097. adCount = int32(len(usableAds))
  1098. usableAdsTemp = nil
  1099. for k := range SKIP_RETRY_MAP {
  1100. delete(SKIP_RETRY_MAP, k)
  1101. }
  1102. // 成功或者失败次数达到重试次数,重置失败次数为0
  1103. failTimes = 0
  1104. // 重置尝试创建实例次数
  1105. runTimes = 0
  1106. startTime = time.Now()
  1107. // for 循环次数+1
  1108. pos++
  1109. if pos < sum && EACH {
  1110. text := fmt.Sprintf("正在尝试创建第 %d 个实例...⏳\n区域: %s\n实例配置: %s\nOCPU计数: %g\n内存(GB): %g\n引导卷(GB): %g\n创建个数: %d", pos+1, oracle.Region, *shape.Shape, *shape.Ocpus, *shape.MemoryInGBs, bootVolumeSize, sum)
  1111. sendMessage("", text)
  1112. }
  1113. }
  1114. return
  1115. }
  1116. func sleepRandomSecond(min, max int32) {
  1117. var second int32
  1118. if min <= 0 || max <= 0 {
  1119. second = 1
  1120. } else if min >= max {
  1121. second = max
  1122. } else {
  1123. second = rand.Int31n(max-min) + min
  1124. }
  1125. printf("Sleep %d Second...\n", second)
  1126. time.Sleep(time.Duration(second) * time.Second)
  1127. }
  1128. // ExampleLaunchInstance does create an instance
  1129. // NOTE: launch instance will create a new instance and VCN. please make sure delete the instance
  1130. // after execute this sample code, otherwise, you will be charged for the running instance
  1131. func ExampleLaunchInstance() {
  1132. c, err := core.NewComputeClientWithConfigurationProvider(provider)
  1133. helpers.FatalIfError(err)
  1134. networkClient, err := core.NewVirtualNetworkClientWithConfigurationProvider(provider)
  1135. helpers.FatalIfError(err)
  1136. ctx := context.Background()
  1137. // create the launch instance request
  1138. request := core.LaunchInstanceRequest{}
  1139. request.CompartmentId = common.String(oracle.Tenancy)
  1140. request.DisplayName = common.String(instance.InstanceDisplayName)
  1141. request.AvailabilityDomain = common.String(instance.AvailabilityDomain)
  1142. // create a subnet or get the one already created
  1143. subnet, err := CreateOrGetNetworkInfrastructure(ctx, networkClient)
  1144. helpers.FatalIfError(err)
  1145. fmt.Println("subnet created")
  1146. request.CreateVnicDetails = &core.CreateVnicDetails{SubnetId: subnet.Id}
  1147. // get a image
  1148. images, err := listImages(ctx, c)
  1149. helpers.FatalIfError(err)
  1150. image := images[0]
  1151. fmt.Println("list images")
  1152. request.SourceDetails = core.InstanceSourceViaImageDetails{
  1153. ImageId: image.Id,
  1154. BootVolumeSizeInGBs: common.Int64(instance.BootVolumeSizeInGBs),
  1155. }
  1156. // use [config.Shape] to create instance
  1157. request.Shape = common.String(instance.Shape)
  1158. request.ShapeConfig = &core.LaunchInstanceShapeConfigDetails{
  1159. Ocpus: common.Float32(instance.Ocpus),
  1160. MemoryInGBs: common.Float32(instance.MemoryInGBs),
  1161. }
  1162. // add ssh_authorized_keys
  1163. //metaData := map[string]string{
  1164. // "ssh_authorized_keys": config.SSH_Public_Key,
  1165. //}
  1166. //request.Metadata = metaData
  1167. request.Metadata = map[string]string{"ssh_authorized_keys": instance.SSH_Public_Key}
  1168. // default retry policy will retry on non-200 response
  1169. request.RequestMetadata = helpers.GetRequestMetadataWithDefaultRetryPolicy()
  1170. createResp, err := c.LaunchInstance(ctx, request)
  1171. helpers.FatalIfError(err)
  1172. fmt.Println("launching instance")
  1173. // should retry condition check which returns a bool value indicating whether to do retry or not
  1174. // it checks the lifecycle status equals to Running or not for this case
  1175. shouldRetryFunc := func(r common.OCIOperationResponse) bool {
  1176. if converted, ok := r.Response.(core.GetInstanceResponse); ok {
  1177. return converted.LifecycleState != core.InstanceLifecycleStateRunning
  1178. }
  1179. return true
  1180. }
  1181. // create get instance request with a retry policy which takes a function
  1182. // to determine shouldRetry or not
  1183. pollingGetRequest := core.GetInstanceRequest{
  1184. InstanceId: createResp.Instance.Id,
  1185. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
  1186. }
  1187. instance, pollError := c.GetInstance(ctx, pollingGetRequest)
  1188. helpers.FatalIfError(pollError)
  1189. fmt.Println("instance launched")
  1190. // 创建辅助 VNIC 并将其附加到指定的实例
  1191. attachVnicResponse, err := c.AttachVnic(context.Background(), core.AttachVnicRequest{
  1192. AttachVnicDetails: core.AttachVnicDetails{
  1193. CreateVnicDetails: &core.CreateVnicDetails{
  1194. SubnetId: subnet.Id,
  1195. AssignPublicIp: common.Bool(true),
  1196. },
  1197. InstanceId: instance.Id,
  1198. },
  1199. })
  1200. helpers.FatalIfError(err)
  1201. fmt.Println("vnic attached")
  1202. vnicState := attachVnicResponse.VnicAttachment.LifecycleState
  1203. for vnicState != core.VnicAttachmentLifecycleStateAttached {
  1204. time.Sleep(15 * time.Second)
  1205. getVnicAttachmentRequest, err := c.GetVnicAttachment(context.Background(), core.GetVnicAttachmentRequest{
  1206. VnicAttachmentId: attachVnicResponse.Id,
  1207. })
  1208. helpers.FatalIfError(err)
  1209. vnicState = getVnicAttachmentRequest.VnicAttachment.LifecycleState
  1210. }
  1211. // 分离并删除指定的辅助 VNIC
  1212. _, err = c.DetachVnic(context.Background(), core.DetachVnicRequest{
  1213. VnicAttachmentId: attachVnicResponse.Id,
  1214. })
  1215. helpers.FatalIfError(err)
  1216. fmt.Println("vnic dettached")
  1217. defer func() {
  1218. terminateInstance(createResp.Id)
  1219. client, clerr := core.NewVirtualNetworkClientWithConfigurationProvider(common.DefaultConfigProvider())
  1220. helpers.FatalIfError(clerr)
  1221. vcnID := subnet.VcnId
  1222. deleteSubnet(ctx, client, subnet.Id)
  1223. deleteVcn(ctx, client, vcnID)
  1224. }()
  1225. // Output:
  1226. // subnet created
  1227. // list images
  1228. // list shapes
  1229. // launching instance
  1230. // instance launched
  1231. // vnic attached
  1232. // vnic dettached
  1233. // terminating instance
  1234. // instance terminated
  1235. // deleteing subnet
  1236. // subnet deleted
  1237. // deleteing VCN
  1238. // VCN deleted
  1239. }
  1240. func getProvider(oracle Oracle) (common.ConfigurationProvider, error) {
  1241. content, err := ioutil.ReadFile(oracle.Key_file)
  1242. if err != nil {
  1243. return nil, err
  1244. }
  1245. privateKey := string(content)
  1246. privateKeyPassphrase := common.String(oracle.Key_password)
  1247. return common.NewRawConfigurationProvider(oracle.Tenancy, oracle.User, oracle.Region, oracle.Fingerprint, privateKey, privateKeyPassphrase), nil
  1248. }
  1249. // 创建或获取基础网络设施
  1250. func CreateOrGetNetworkInfrastructure(ctx context.Context, c core.VirtualNetworkClient) (subnet core.Subnet, err error) {
  1251. var vcn core.Vcn
  1252. vcn, err = createOrGetVcn(ctx, c)
  1253. if err != nil {
  1254. return
  1255. }
  1256. var gateway core.InternetGateway
  1257. gateway, err = createOrGetInternetGateway(c, vcn.Id)
  1258. if err != nil {
  1259. return
  1260. }
  1261. _, err = createOrGetRouteTable(c, gateway.Id, vcn.Id)
  1262. if err != nil {
  1263. return
  1264. }
  1265. subnet, err = createOrGetSubnetWithDetails(
  1266. ctx, c, vcn.Id,
  1267. common.String(instance.SubnetDisplayName),
  1268. common.String("10.0.0.0/24"),
  1269. common.String("subnetdns"),
  1270. common.String(instance.AvailabilityDomain))
  1271. return
  1272. }
  1273. // CreateOrGetSubnetWithDetails either creates a new Virtual Cloud Network (VCN) or get the one already exist
  1274. // with detail info
  1275. func createOrGetSubnetWithDetails(ctx context.Context, c core.VirtualNetworkClient, vcnID *string,
  1276. displayName *string, cidrBlock *string, dnsLabel *string, availableDomain *string) (subnet core.Subnet, err error) {
  1277. var subnets []core.Subnet
  1278. subnets, err = listSubnets(ctx, c, vcnID)
  1279. if err != nil {
  1280. return
  1281. }
  1282. if displayName == nil {
  1283. displayName = common.String(instance.SubnetDisplayName)
  1284. }
  1285. if len(subnets) > 0 && *displayName == "" {
  1286. subnet = subnets[0]
  1287. return
  1288. }
  1289. // check if the subnet has already been created
  1290. for _, element := range subnets {
  1291. if *element.DisplayName == *displayName {
  1292. // find the subnet, return it
  1293. subnet = element
  1294. return
  1295. }
  1296. }
  1297. // create a new subnet
  1298. printf("开始创建Subnet(没有可用的Subnet,或指定的Subnet不存在)\n")
  1299. // 子网名称为空,以当前时间为名称创建子网
  1300. if *displayName == "" {
  1301. displayName = common.String(time.Now().Format("subnet-20060102-1504"))
  1302. }
  1303. request := core.CreateSubnetRequest{}
  1304. //request.AvailabilityDomain = availableDomain //省略此属性创建区域性子网(regional subnet),提供此属性创建特定于可用性域的子网。建议创建区域性子网。
  1305. request.CompartmentId = &oracle.Tenancy
  1306. request.CidrBlock = cidrBlock
  1307. request.DisplayName = displayName
  1308. request.DnsLabel = dnsLabel
  1309. request.RequestMetadata = getCustomRequestMetadataWithRetryPolicy()
  1310. request.VcnId = vcnID
  1311. var r core.CreateSubnetResponse
  1312. r, err = c.CreateSubnet(ctx, request)
  1313. if err != nil {
  1314. return
  1315. }
  1316. // retry condition check, stop unitl return true
  1317. pollUntilAvailable := func(r common.OCIOperationResponse) bool {
  1318. if converted, ok := r.Response.(core.GetSubnetResponse); ok {
  1319. return converted.LifecycleState != core.SubnetLifecycleStateAvailable
  1320. }
  1321. return true
  1322. }
  1323. pollGetRequest := core.GetSubnetRequest{
  1324. SubnetId: r.Id,
  1325. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(pollUntilAvailable),
  1326. }
  1327. // wait for lifecyle become running
  1328. _, err = c.GetSubnet(ctx, pollGetRequest)
  1329. if err != nil {
  1330. return
  1331. }
  1332. // update the security rules
  1333. getReq := core.GetSecurityListRequest{
  1334. SecurityListId: common.String(r.SecurityListIds[0]),
  1335. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1336. }
  1337. var getResp core.GetSecurityListResponse
  1338. getResp, err = c.GetSecurityList(ctx, getReq)
  1339. if err != nil {
  1340. return
  1341. }
  1342. // this security rule allows remote control the instance
  1343. /*portRange := core.PortRange{
  1344. Max: common.Int(1521),
  1345. Min: common.Int(1521),
  1346. }*/
  1347. newRules := append(getResp.IngressSecurityRules, core.IngressSecurityRule{
  1348. //Protocol: common.String("6"), // TCP
  1349. Protocol: common.String("all"), // 允许所有协议
  1350. Source: common.String("0.0.0.0/0"),
  1351. /*TcpOptions: &core.TcpOptions{
  1352. DestinationPortRange: &portRange, // 省略该参数,允许所有目标端口。
  1353. },*/
  1354. })
  1355. updateReq := core.UpdateSecurityListRequest{
  1356. SecurityListId: common.String(r.SecurityListIds[0]),
  1357. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1358. }
  1359. updateReq.IngressSecurityRules = newRules
  1360. _, err = c.UpdateSecurityList(ctx, updateReq)
  1361. if err != nil {
  1362. return
  1363. }
  1364. printf("Subnet创建成功: %s\n", *r.Subnet.DisplayName)
  1365. subnet = r.Subnet
  1366. return
  1367. }
  1368. // 列出指定虚拟云网络 (VCN) 中的所有子网
  1369. func listSubnets(ctx context.Context, c core.VirtualNetworkClient, vcnID *string) (subnets []core.Subnet, err error) {
  1370. request := core.ListSubnetsRequest{
  1371. CompartmentId: &oracle.Tenancy,
  1372. VcnId: vcnID,
  1373. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1374. }
  1375. var r core.ListSubnetsResponse
  1376. r, err = c.ListSubnets(ctx, request)
  1377. if err != nil {
  1378. return
  1379. }
  1380. subnets = r.Items
  1381. return
  1382. }
  1383. // 创建一个新的虚拟云网络 (VCN) 或获取已经存在的虚拟云网络
  1384. func createOrGetVcn(ctx context.Context, c core.VirtualNetworkClient) (core.Vcn, error) {
  1385. var vcn core.Vcn
  1386. vcnItems, err := listVcns(ctx, c)
  1387. if err != nil {
  1388. return vcn, err
  1389. }
  1390. displayName := common.String(instance.VcnDisplayName)
  1391. if len(vcnItems) > 0 && *displayName == "" {
  1392. vcn = vcnItems[0]
  1393. return vcn, err
  1394. }
  1395. for _, element := range vcnItems {
  1396. if *element.DisplayName == instance.VcnDisplayName {
  1397. // VCN already created, return it
  1398. vcn = element
  1399. return vcn, err
  1400. }
  1401. }
  1402. // create a new VCN
  1403. printf("开始创建VCN(没有可用的VCN,或指定的VCN不存在)\n")
  1404. if *displayName == "" {
  1405. displayName = common.String(time.Now().Format("vcn-20060102-1504"))
  1406. }
  1407. request := core.CreateVcnRequest{}
  1408. request.RequestMetadata = getCustomRequestMetadataWithRetryPolicy()
  1409. request.CidrBlock = common.String("10.0.0.0/16")
  1410. request.CompartmentId = common.String(oracle.Tenancy)
  1411. request.DisplayName = displayName
  1412. request.DnsLabel = common.String("vcndns")
  1413. r, err := c.CreateVcn(ctx, request)
  1414. if err != nil {
  1415. return vcn, err
  1416. }
  1417. printf("VCN创建成功: %s\n", *r.Vcn.DisplayName)
  1418. vcn = r.Vcn
  1419. return vcn, err
  1420. }
  1421. // 列出所有虚拟云网络 (VCN)
  1422. func listVcns(ctx context.Context, c core.VirtualNetworkClient) ([]core.Vcn, error) {
  1423. request := core.ListVcnsRequest{
  1424. CompartmentId: &oracle.Tenancy,
  1425. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1426. }
  1427. r, err := c.ListVcns(ctx, request)
  1428. if err != nil {
  1429. return nil, err
  1430. }
  1431. return r.Items, err
  1432. }
  1433. // 创建或者获取 Internet 网关
  1434. func createOrGetInternetGateway(c core.VirtualNetworkClient, vcnID *string) (core.InternetGateway, error) {
  1435. //List Gateways
  1436. var gateway core.InternetGateway
  1437. listGWRequest := core.ListInternetGatewaysRequest{
  1438. CompartmentId: &oracle.Tenancy,
  1439. VcnId: vcnID,
  1440. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1441. }
  1442. listGWRespone, err := c.ListInternetGateways(ctx, listGWRequest)
  1443. if err != nil {
  1444. printf("Internet gateway list error: %s\n", err.Error())
  1445. return gateway, err
  1446. }
  1447. if len(listGWRespone.Items) >= 1 {
  1448. //Gateway with name already exists
  1449. gateway = listGWRespone.Items[0]
  1450. } else {
  1451. //Create new Gateway
  1452. printf("开始创建Internet网关\n")
  1453. enabled := true
  1454. createGWDetails := core.CreateInternetGatewayDetails{
  1455. CompartmentId: &oracle.Tenancy,
  1456. IsEnabled: &enabled,
  1457. VcnId: vcnID,
  1458. }
  1459. createGWRequest := core.CreateInternetGatewayRequest{
  1460. CreateInternetGatewayDetails: createGWDetails,
  1461. RequestMetadata: getCustomRequestMetadataWithRetryPolicy()}
  1462. createGWResponse, err := c.CreateInternetGateway(ctx, createGWRequest)
  1463. if err != nil {
  1464. printf("Internet gateway create error: %s\n", err.Error())
  1465. return gateway, err
  1466. }
  1467. gateway = createGWResponse.InternetGateway
  1468. printf("Internet网关创建成功: %s\n", *gateway.DisplayName)
  1469. }
  1470. return gateway, err
  1471. }
  1472. // 创建或者获取路由表
  1473. func createOrGetRouteTable(c core.VirtualNetworkClient, gatewayID, VcnID *string) (routeTable core.RouteTable, err error) {
  1474. //List Route Table
  1475. listRTRequest := core.ListRouteTablesRequest{
  1476. CompartmentId: &oracle.Tenancy,
  1477. VcnId: VcnID,
  1478. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1479. }
  1480. var listRTResponse core.ListRouteTablesResponse
  1481. listRTResponse, err = c.ListRouteTables(ctx, listRTRequest)
  1482. if err != nil {
  1483. printf("Route table list error: %s\n", err.Error())
  1484. return
  1485. }
  1486. cidrRange := "0.0.0.0/0"
  1487. rr := core.RouteRule{
  1488. NetworkEntityId: gatewayID,
  1489. Destination: &cidrRange,
  1490. DestinationType: core.RouteRuleDestinationTypeCidrBlock,
  1491. }
  1492. if len(listRTResponse.Items) >= 1 {
  1493. //Default Route Table found and has at least 1 route rule
  1494. if len(listRTResponse.Items[0].RouteRules) >= 1 {
  1495. routeTable = listRTResponse.Items[0]
  1496. //Default Route table needs route rule adding
  1497. } else {
  1498. printf("路由表未添加规则,开始添加Internet路由规则\n")
  1499. updateRTDetails := core.UpdateRouteTableDetails{
  1500. RouteRules: []core.RouteRule{rr},
  1501. }
  1502. updateRTRequest := core.UpdateRouteTableRequest{
  1503. RtId: listRTResponse.Items[0].Id,
  1504. UpdateRouteTableDetails: updateRTDetails,
  1505. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1506. }
  1507. var updateRTResponse core.UpdateRouteTableResponse
  1508. updateRTResponse, err = c.UpdateRouteTable(ctx, updateRTRequest)
  1509. if err != nil {
  1510. printf("Error updating route table: %s\n", err)
  1511. return
  1512. }
  1513. printf("Internet路由规则添加成功\n")
  1514. routeTable = updateRTResponse.RouteTable
  1515. }
  1516. } else {
  1517. //No default route table found
  1518. printf("Error could not find VCN default route table, VCN OCID: %s Could not find route table.\n", *VcnID)
  1519. }
  1520. return
  1521. }
  1522. // 获取符合条件系统镜像中的第一个
  1523. func GetImage(ctx context.Context, c core.ComputeClient) (image core.Image, err error) {
  1524. var images []core.Image
  1525. images, err = listImages(ctx, c)
  1526. if err != nil {
  1527. return
  1528. }
  1529. if len(images) > 0 {
  1530. image = images[0]
  1531. } else {
  1532. err = fmt.Errorf("未找到[%s %s]的镜像, 或该镜像不支持[%s]", instance.OperatingSystem, instance.OperatingSystemVersion, instance.Shape)
  1533. }
  1534. return
  1535. }
  1536. // 列出所有符合条件的系统镜像
  1537. func listImages(ctx context.Context, c core.ComputeClient) ([]core.Image, error) {
  1538. if instance.OperatingSystem == "" || instance.OperatingSystemVersion == "" {
  1539. return nil, errors.New("操作系统类型和版本不能为空, 请检查配置文件")
  1540. }
  1541. request := core.ListImagesRequest{
  1542. CompartmentId: common.String(oracle.Tenancy),
  1543. OperatingSystem: common.String(instance.OperatingSystem),
  1544. OperatingSystemVersion: common.String(instance.OperatingSystemVersion),
  1545. Shape: common.String(instance.Shape),
  1546. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1547. }
  1548. r, err := c.ListImages(ctx, request)
  1549. return r.Items, err
  1550. }
  1551. func getShape(imageId *string, shapeName string) (core.Shape, error) {
  1552. var shape core.Shape
  1553. shapes, err := listShapes(ctx, computeClient, imageId)
  1554. if err != nil {
  1555. return shape, err
  1556. }
  1557. for _, s := range shapes {
  1558. if strings.EqualFold(*s.Shape, shapeName) {
  1559. shape = s
  1560. return shape, nil
  1561. }
  1562. }
  1563. err = errors.New("没有符合条件的Shape")
  1564. return shape, err
  1565. }
  1566. // ListShapes Lists the shapes that can be used to launch an instance within the specified compartment.
  1567. func listShapes(ctx context.Context, c core.ComputeClient, imageID *string) ([]core.Shape, error) {
  1568. request := core.ListShapesRequest{
  1569. CompartmentId: common.String(oracle.Tenancy),
  1570. ImageId: imageID,
  1571. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1572. }
  1573. r, err := c.ListShapes(ctx, request)
  1574. if err == nil && (r.Items == nil || len(r.Items) == 0) {
  1575. err = errors.New("没有符合条件的Shape")
  1576. }
  1577. return r.Items, err
  1578. }
  1579. // 列出符合条件的可用性域
  1580. func ListAvailabilityDomains() ([]identity.AvailabilityDomain, error) {
  1581. req := identity.ListAvailabilityDomainsRequest{
  1582. CompartmentId: common.String(oracle.Tenancy),
  1583. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1584. }
  1585. resp, err := identityClient.ListAvailabilityDomains(ctx, req)
  1586. return resp.Items, err
  1587. }
  1588. func ListInstances(ctx context.Context, c core.ComputeClient) ([]core.Instance, error) {
  1589. req := core.ListInstancesRequest{
  1590. CompartmentId: common.String(oracle.Tenancy),
  1591. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1592. }
  1593. resp, err := c.ListInstances(ctx, req)
  1594. return resp.Items, err
  1595. }
  1596. func ListVnicAttachments(ctx context.Context, c core.ComputeClient, instanceId *string) ([]core.VnicAttachment, error) {
  1597. req := core.ListVnicAttachmentsRequest{
  1598. CompartmentId: common.String(oracle.Tenancy),
  1599. RequestMetadata: getCustomRequestMetadataWithRetryPolicy()}
  1600. if instanceId != nil && *instanceId != "" {
  1601. req.InstanceId = instanceId
  1602. }
  1603. resp, err := c.ListVnicAttachments(ctx, req)
  1604. return resp.Items, err
  1605. }
  1606. func GetVnic(ctx context.Context, c core.VirtualNetworkClient, vnicID *string) (core.Vnic, error) {
  1607. req := core.GetVnicRequest{
  1608. VnicId: vnicID,
  1609. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1610. }
  1611. resp, err := c.GetVnic(ctx, req)
  1612. if err != nil && resp.RawResponse != nil {
  1613. err = errors.New(resp.RawResponse.Status)
  1614. }
  1615. return resp.Vnic, err
  1616. }
  1617. // 终止实例
  1618. // https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/Instance/TerminateInstance
  1619. func terminateInstance(id *string) error {
  1620. request := core.TerminateInstanceRequest{
  1621. InstanceId: id,
  1622. PreserveBootVolume: common.Bool(false),
  1623. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1624. }
  1625. _, err := computeClient.TerminateInstance(ctx, request)
  1626. return err
  1627. //fmt.Println("terminating instance")
  1628. /*
  1629. // should retry condition check which returns a bool value indicating whether to do retry or not
  1630. // it checks the lifecycle status equals to Terminated or not for this case
  1631. shouldRetryFunc := func(r common.OCIOperationResponse) bool {
  1632. if converted, ok := r.Response.(core.GetInstanceResponse); ok {
  1633. return converted.LifecycleState != core.InstanceLifecycleStateTerminated
  1634. }
  1635. return true
  1636. }
  1637. pollGetRequest := core.GetInstanceRequest{
  1638. InstanceId: id,
  1639. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
  1640. }
  1641. _, pollErr := c.GetInstance(ctx, pollGetRequest)
  1642. helpers.FatalIfError(pollErr)
  1643. fmt.Println("instance terminated")
  1644. */
  1645. }
  1646. // 删除虚拟云网络
  1647. func deleteVcn(ctx context.Context, c core.VirtualNetworkClient, id *string) {
  1648. request := core.DeleteVcnRequest{
  1649. VcnId: id,
  1650. RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
  1651. }
  1652. fmt.Println("deleteing VCN")
  1653. _, err := c.DeleteVcn(ctx, request)
  1654. helpers.FatalIfError(err)
  1655. // should retry condition check which returns a bool value indicating whether to do retry or not
  1656. // it checks the lifecycle status equals to Terminated or not for this case
  1657. shouldRetryFunc := func(r common.OCIOperationResponse) bool {
  1658. if serviceError, ok := common.IsServiceError(r.Error); ok && serviceError.GetHTTPStatusCode() == 404 {
  1659. // resource been deleted, stop retry
  1660. return false
  1661. }
  1662. if converted, ok := r.Response.(core.GetVcnResponse); ok {
  1663. return converted.LifecycleState != core.VcnLifecycleStateTerminated
  1664. }
  1665. return true
  1666. }
  1667. pollGetRequest := core.GetVcnRequest{
  1668. VcnId: id,
  1669. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
  1670. }
  1671. _, pollErr := c.GetVcn(ctx, pollGetRequest)
  1672. if serviceError, ok := common.IsServiceError(pollErr); !ok ||
  1673. (ok && serviceError.GetHTTPStatusCode() != 404) {
  1674. // fail if the error is not service error or
  1675. // if the error is service error and status code not equals to 404
  1676. helpers.FatalIfError(pollErr)
  1677. }
  1678. fmt.Println("VCN deleted")
  1679. }
  1680. // 删除子网
  1681. func deleteSubnet(ctx context.Context, c core.VirtualNetworkClient, id *string) {
  1682. request := core.DeleteSubnetRequest{
  1683. SubnetId: id,
  1684. RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
  1685. }
  1686. _, err := c.DeleteSubnet(context.Background(), request)
  1687. helpers.FatalIfError(err)
  1688. fmt.Println("deleteing subnet")
  1689. // should retry condition check which returns a bool value indicating whether to do retry or not
  1690. // it checks the lifecycle status equals to Terminated or not for this case
  1691. shouldRetryFunc := func(r common.OCIOperationResponse) bool {
  1692. if serviceError, ok := common.IsServiceError(r.Error); ok && serviceError.GetHTTPStatusCode() == 404 {
  1693. // resource been deleted
  1694. return false
  1695. }
  1696. if converted, ok := r.Response.(core.GetSubnetResponse); ok {
  1697. return converted.LifecycleState != core.SubnetLifecycleStateTerminated
  1698. }
  1699. return true
  1700. }
  1701. pollGetRequest := core.GetSubnetRequest{
  1702. SubnetId: id,
  1703. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
  1704. }
  1705. _, pollErr := c.GetSubnet(ctx, pollGetRequest)
  1706. if serviceError, ok := common.IsServiceError(pollErr); !ok ||
  1707. (ok && serviceError.GetHTTPStatusCode() != 404) {
  1708. // fail if the error is not service error or
  1709. // if the error is service error and status code not equals to 404
  1710. helpers.FatalIfError(pollErr)
  1711. }
  1712. fmt.Println("subnet deleted")
  1713. }
  1714. func getInstance(instanceId *string) (core.Instance, error) {
  1715. req := core.GetInstanceRequest{
  1716. InstanceId: instanceId,
  1717. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1718. }
  1719. resp, err := computeClient.GetInstance(ctx, req)
  1720. return resp.Instance, err
  1721. }
  1722. func instanceAction(instanceId *string, action core.InstanceActionActionEnum) (ins core.Instance, err error) {
  1723. req := core.InstanceActionRequest{
  1724. InstanceId: instanceId,
  1725. Action: action,
  1726. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1727. }
  1728. resp, err := computeClient.InstanceAction(ctx, req)
  1729. ins = resp.Instance
  1730. return
  1731. }
  1732. func changePublicIp(vnics []core.Vnic) (publicIp core.PublicIp, err error) {
  1733. var vnic core.Vnic
  1734. for _, v := range vnics {
  1735. if *v.IsPrimary {
  1736. vnic = v
  1737. }
  1738. }
  1739. fmt.Println("正在获取私有IP...")
  1740. var privateIps []core.PrivateIp
  1741. privateIps, err = getPrivateIps(vnic.Id)
  1742. if err != nil {
  1743. printlnErr("获取私有IP失败", err.Error())
  1744. return
  1745. }
  1746. var privateIp core.PrivateIp
  1747. for _, p := range privateIps {
  1748. if *p.IsPrimary {
  1749. privateIp = p
  1750. }
  1751. }
  1752. fmt.Println("正在获取公共IP OCID...")
  1753. publicIp, err = getPublicIp(privateIp.Id)
  1754. if err != nil {
  1755. printlnErr("获取公共IP OCID 失败", err.Error())
  1756. }
  1757. fmt.Println("正在删除公共IP...")
  1758. _, err = deletePublicIp(publicIp.Id)
  1759. if err != nil {
  1760. printlnErr("删除公共IP 失败", err.Error())
  1761. }
  1762. time.Sleep(3 * time.Second)
  1763. fmt.Println("正在创建公共IP...")
  1764. publicIp, err = createPublicIp(privateIp.Id)
  1765. return
  1766. }
  1767. func getInstanceVnics(instanceId *string) (vnics []core.Vnic, err error) {
  1768. vnicAttachments, err := ListVnicAttachments(ctx, computeClient, instanceId)
  1769. if err != nil {
  1770. return
  1771. }
  1772. for _, vnicAttachment := range vnicAttachments {
  1773. vnic, vnicErr := GetVnic(ctx, networkClient, vnicAttachment.VnicId)
  1774. if vnicErr != nil {
  1775. printf("GetVnic error: %s\n", vnicErr.Error())
  1776. continue
  1777. }
  1778. vnics = append(vnics, vnic)
  1779. }
  1780. return
  1781. }
  1782. // 更新指定的VNIC
  1783. func updateVnic(vnicId *string) (core.Vnic, error) {
  1784. req := core.UpdateVnicRequest{
  1785. VnicId: vnicId,
  1786. UpdateVnicDetails: core.UpdateVnicDetails{SkipSourceDestCheck: common.Bool(true)},
  1787. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1788. }
  1789. resp, err := networkClient.UpdateVnic(ctx, req)
  1790. return resp.Vnic, err
  1791. }
  1792. // 获取指定VNIC的私有IP
  1793. func getPrivateIps(vnicId *string) ([]core.PrivateIp, error) {
  1794. req := core.ListPrivateIpsRequest{
  1795. VnicId: vnicId,
  1796. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1797. }
  1798. resp, err := networkClient.ListPrivateIps(ctx, req)
  1799. if err == nil && (resp.Items == nil || len(resp.Items) == 0) {
  1800. err = errors.New("私有IP为空")
  1801. }
  1802. return resp.Items, err
  1803. }
  1804. // 获取分配给指定私有IP的公共IP
  1805. func getPublicIp(privateIpId *string) (core.PublicIp, error) {
  1806. req := core.GetPublicIpByPrivateIpIdRequest{
  1807. GetPublicIpByPrivateIpIdDetails: core.GetPublicIpByPrivateIpIdDetails{PrivateIpId: privateIpId},
  1808. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1809. }
  1810. resp, err := networkClient.GetPublicIpByPrivateIpId(ctx, req)
  1811. if err == nil && resp.PublicIp.Id == nil {
  1812. err = errors.New("未分配公共IP")
  1813. }
  1814. return resp.PublicIp, err
  1815. }
  1816. // 删除公共IP
  1817. // 取消分配并删除指定公共IP(临时或保留)
  1818. // 如果仅需要取消分配保留的公共IP并将保留的公共IP返回到保留公共IP池,请使用updatePublicIp方法。
  1819. func deletePublicIp(publicIpId *string) (core.DeletePublicIpResponse, error) {
  1820. req := core.DeletePublicIpRequest{
  1821. PublicIpId: publicIpId,
  1822. RequestMetadata: getCustomRequestMetadataWithRetryPolicy()}
  1823. return networkClient.DeletePublicIp(ctx, req)
  1824. }
  1825. // 创建公共IP
  1826. // 通过Lifetime指定创建临时公共IP还是保留公共IP。
  1827. // 创建临时公共IP,必须指定privateIpId,将临时公共IP分配给指定私有IP。
  1828. // 创建保留公共IP,可以不指定privateIpId。稍后可以使用updatePublicIp方法分配给私有IP。
  1829. func createPublicIp(privateIpId *string) (core.PublicIp, error) {
  1830. var publicIp core.PublicIp
  1831. req := core.CreatePublicIpRequest{
  1832. CreatePublicIpDetails: core.CreatePublicIpDetails{
  1833. CompartmentId: common.String(oracle.Tenancy),
  1834. Lifetime: core.CreatePublicIpDetailsLifetimeEphemeral,
  1835. PrivateIpId: privateIpId,
  1836. },
  1837. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1838. }
  1839. resp, err := networkClient.CreatePublicIp(ctx, req)
  1840. publicIp = resp.PublicIp
  1841. return publicIp, err
  1842. }
  1843. // 更新保留公共IP
  1844. // 1. 将保留的公共IP分配给指定的私有IP。如果该公共IP已经分配给私有IP,会取消分配,然后重新分配给指定的私有IP。
  1845. // 2. PrivateIpId设置为空字符串,公共IP取消分配到关联的私有IP。
  1846. func updatePublicIp(publicIpId *string, privateIpId *string) (core.PublicIp, error) {
  1847. req := core.UpdatePublicIpRequest{
  1848. PublicIpId: publicIpId,
  1849. UpdatePublicIpDetails: core.UpdatePublicIpDetails{
  1850. PrivateIpId: privateIpId,
  1851. },
  1852. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1853. }
  1854. resp, err := networkClient.UpdatePublicIp(ctx, req)
  1855. return resp.PublicIp, err
  1856. }
  1857. // 根据实例OCID获取公共IP
  1858. func getInstancePublicIps(instanceId *string) (ips []string, err error) {
  1859. // 多次尝试,避免刚抢购到实例,实例正在预配获取不到公共IP。
  1860. var ins core.Instance
  1861. for i := 0; i < 100; i++ {
  1862. fmt.Println(i, ins.LifecycleState)
  1863. if ins.LifecycleState != core.InstanceLifecycleStateRunning {
  1864. ins, err = getInstance(instanceId)
  1865. fmt.Println("instance:", ins.LifecycleState, err)
  1866. if err != nil {
  1867. continue
  1868. }
  1869. if ins.LifecycleState == core.InstanceLifecycleStateTerminating || ins.LifecycleState == core.InstanceLifecycleStateTerminated {
  1870. err = errors.New("实例已终止😔")
  1871. return
  1872. }
  1873. // if ins.LifecycleState != core.InstanceLifecycleStateRunning {
  1874. // continue
  1875. // }
  1876. }
  1877. var vnicAttachments []core.VnicAttachment
  1878. vnicAttachments, err = ListVnicAttachments(ctx, computeClient, instanceId)
  1879. fmt.Println(vnicAttachments, err)
  1880. if err != nil {
  1881. continue
  1882. }
  1883. if len(vnicAttachments) > 0 {
  1884. for _, vnicAttachment := range vnicAttachments {
  1885. fmt.Println("vnicAttachment:", vnicAttachment.LifecycleState)
  1886. vnic, vnicErr := GetVnic(ctx, networkClient, vnicAttachment.VnicId)
  1887. if vnicErr != nil {
  1888. printf("GetVnic error: %s\n", vnicErr.Error())
  1889. continue
  1890. }
  1891. fmt.Println("vnic:", vnic.LifecycleState)
  1892. if vnic.PublicIp != nil && *vnic.PublicIp != "" {
  1893. ips = append(ips, *vnic.PublicIp)
  1894. }
  1895. }
  1896. return
  1897. }
  1898. time.Sleep(3 * time.Second)
  1899. }
  1900. return
  1901. }
  1902. // 列出引导卷
  1903. func getBootVolumes(availabilityDomain *string) ([]core.BootVolume, error) {
  1904. req := core.ListBootVolumesRequest{
  1905. AvailabilityDomain: availabilityDomain,
  1906. CompartmentId: common.String(oracle.Tenancy),
  1907. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1908. }
  1909. resp, err := storageClient.ListBootVolumes(ctx, req)
  1910. return resp.Items, err
  1911. }
  1912. // 获取指定引导卷
  1913. func getBootVolume(bootVolumeId *string) (core.BootVolume, error) {
  1914. req := core.GetBootVolumeRequest{
  1915. BootVolumeId: bootVolumeId,
  1916. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1917. }
  1918. resp, err := storageClient.GetBootVolume(ctx, req)
  1919. return resp.BootVolume, err
  1920. }
  1921. // 更新引导卷
  1922. func updateBootVolume(bootVolumeId *string, sizeInGBs *int64, vpusPerGB *int64) (core.BootVolume, error) {
  1923. updateBootVolumeDetails := core.UpdateBootVolumeDetails{}
  1924. if sizeInGBs != nil {
  1925. updateBootVolumeDetails.SizeInGBs = sizeInGBs
  1926. }
  1927. if vpusPerGB != nil {
  1928. updateBootVolumeDetails.VpusPerGB = vpusPerGB
  1929. }
  1930. req := core.UpdateBootVolumeRequest{
  1931. BootVolumeId: bootVolumeId,
  1932. UpdateBootVolumeDetails: updateBootVolumeDetails,
  1933. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1934. }
  1935. resp, err := storageClient.UpdateBootVolume(ctx, req)
  1936. return resp.BootVolume, err
  1937. }
  1938. // 删除引导卷
  1939. func deleteBootVolume(bootVolumeId *string) (*http.Response, error) {
  1940. req := core.DeleteBootVolumeRequest{
  1941. BootVolumeId: bootVolumeId,
  1942. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1943. }
  1944. resp, err := storageClient.DeleteBootVolume(ctx, req)
  1945. return resp.RawResponse, err
  1946. }
  1947. // 分离引导卷
  1948. func detachBootVolume(bootVolumeAttachmentId *string) (*http.Response, error) {
  1949. req := core.DetachBootVolumeRequest{
  1950. BootVolumeAttachmentId: bootVolumeAttachmentId,
  1951. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1952. }
  1953. resp, err := computeClient.DetachBootVolume(ctx, req)
  1954. return resp.RawResponse, err
  1955. }
  1956. // 获取引导卷附件
  1957. func listBootVolumeAttachments(availabilityDomain, compartmentId, bootVolumeId *string) ([]core.BootVolumeAttachment, error) {
  1958. req := core.ListBootVolumeAttachmentsRequest{
  1959. AvailabilityDomain: availabilityDomain,
  1960. CompartmentId: compartmentId,
  1961. BootVolumeId: bootVolumeId,
  1962. RequestMetadata: getCustomRequestMetadataWithRetryPolicy(),
  1963. }
  1964. resp, err := computeClient.ListBootVolumeAttachments(ctx, req)
  1965. return resp.Items, err
  1966. }
  1967. func sendMessage(name, text string) (msg Message, err error) {
  1968. if token != "" && chat_id != "" {
  1969. data := url.Values{
  1970. "parse_mode": {"Markdown"},
  1971. "chat_id": {chat_id},
  1972. "text": {"🔰*甲骨文通知* " + name + "\n" + text},
  1973. }
  1974. var req *http.Request
  1975. req, err = http.NewRequest(http.MethodPost, sendMessageUrl, strings.NewReader(data.Encode()))
  1976. if err != nil {
  1977. return
  1978. }
  1979. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  1980. client := common.BaseClient{HTTPClient: &http.Client{}}
  1981. setProxyOrNot(&client)
  1982. var resp *http.Response
  1983. resp, err = client.HTTPClient.Do(req)
  1984. if err != nil {
  1985. return
  1986. }
  1987. var body []byte
  1988. body, err = ioutil.ReadAll(resp.Body)
  1989. if err != nil {
  1990. return
  1991. }
  1992. err = json.Unmarshal(body, &msg)
  1993. if err != nil {
  1994. return
  1995. }
  1996. if !msg.OK {
  1997. err = errors.New(msg.Description)
  1998. return
  1999. }
  2000. }
  2001. return
  2002. }
  2003. func editMessage(messageId int, name, text string) (msg Message, err error) {
  2004. if token != "" && chat_id != "" {
  2005. data := url.Values{
  2006. "parse_mode": {"Markdown"},
  2007. "chat_id": {chat_id},
  2008. "message_id": {strconv.Itoa(messageId)},
  2009. "text": {"🔰*甲骨文通知* " + name + "\n" + text},
  2010. }
  2011. var req *http.Request
  2012. req, err = http.NewRequest(http.MethodPost, editMessageUrl, strings.NewReader(data.Encode()))
  2013. if err != nil {
  2014. return
  2015. }
  2016. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  2017. client := common.BaseClient{HTTPClient: &http.Client{}}
  2018. setProxyOrNot(&client)
  2019. var resp *http.Response
  2020. resp, err = client.HTTPClient.Do(req)
  2021. if err != nil {
  2022. return
  2023. }
  2024. var body []byte
  2025. body, err = ioutil.ReadAll(resp.Body)
  2026. if err != nil {
  2027. return
  2028. }
  2029. err = json.Unmarshal(body, &msg)
  2030. if err != nil {
  2031. return
  2032. }
  2033. if !msg.OK {
  2034. err = errors.New(msg.Description)
  2035. return
  2036. }
  2037. }
  2038. return
  2039. }
  2040. func setProxyOrNot(client *common.BaseClient) {
  2041. if proxy != "" {
  2042. proxyURL, err := url.Parse(proxy)
  2043. if err != nil {
  2044. printlnErr("URL parse failed", err.Error())
  2045. return
  2046. }
  2047. client.HTTPClient = &http.Client{
  2048. Transport: &http.Transport{
  2049. Proxy: http.ProxyURL(proxyURL),
  2050. },
  2051. }
  2052. }
  2053. }
  2054. func getInstanceState(state core.InstanceLifecycleStateEnum) string {
  2055. var friendlyState string
  2056. switch state {
  2057. case core.InstanceLifecycleStateMoving:
  2058. friendlyState = "正在移动"
  2059. case core.InstanceLifecycleStateProvisioning:
  2060. friendlyState = "正在预配"
  2061. case core.InstanceLifecycleStateRunning:
  2062. friendlyState = "正在运行"
  2063. case core.InstanceLifecycleStateStarting:
  2064. friendlyState = "正在启动"
  2065. case core.InstanceLifecycleStateStopping:
  2066. friendlyState = "正在停止"
  2067. case core.InstanceLifecycleStateStopped:
  2068. friendlyState = "已停止 "
  2069. case core.InstanceLifecycleStateTerminating:
  2070. friendlyState = "正在终止"
  2071. case core.InstanceLifecycleStateTerminated:
  2072. friendlyState = "已终止 "
  2073. default:
  2074. friendlyState = string(state)
  2075. }
  2076. return friendlyState
  2077. }
  2078. func getBootVolumeState(state core.BootVolumeLifecycleStateEnum) string {
  2079. var friendlyState string
  2080. switch state {
  2081. case core.BootVolumeLifecycleStateProvisioning:
  2082. friendlyState = "正在预配"
  2083. case core.BootVolumeLifecycleStateRestoring:
  2084. friendlyState = "正在恢复"
  2085. case core.BootVolumeLifecycleStateAvailable:
  2086. friendlyState = "可用  "
  2087. case core.BootVolumeLifecycleStateTerminating:
  2088. friendlyState = "正在终止"
  2089. case core.BootVolumeLifecycleStateTerminated:
  2090. friendlyState = "已终止 "
  2091. case core.BootVolumeLifecycleStateFaulty:
  2092. friendlyState = "故障  "
  2093. default:
  2094. friendlyState = string(state)
  2095. }
  2096. return friendlyState
  2097. }
  2098. func fmtDuration(d time.Duration) string {
  2099. if d.Seconds() < 1 {
  2100. return "< 1 秒"
  2101. }
  2102. var buffer bytes.Buffer
  2103. //days := int(d.Hours() / 24)
  2104. //hours := int(math.Mod(d.Hours(), 24))
  2105. //minutes := int(math.Mod(d.Minutes(), 60))
  2106. //seconds := int(math.Mod(d.Seconds(), 60))
  2107. days := int(d / (time.Hour * 24))
  2108. hours := int((d % (time.Hour * 24)).Hours())
  2109. minutes := int((d % time.Hour).Minutes())
  2110. seconds := int((d % time.Minute).Seconds())
  2111. if days > 0 {
  2112. buffer.WriteString(fmt.Sprintf("%d 天 ", days))
  2113. }
  2114. if hours > 0 {
  2115. buffer.WriteString(fmt.Sprintf("%d 时 ", hours))
  2116. }
  2117. if minutes > 0 {
  2118. buffer.WriteString(fmt.Sprintf("%d 分 ", minutes))
  2119. }
  2120. if seconds > 0 {
  2121. buffer.WriteString(fmt.Sprintf("%d 秒", seconds))
  2122. }
  2123. return buffer.String()
  2124. }
  2125. func printf(format string, a ...interface{}) {
  2126. fmt.Printf("%s ", time.Now().Format("2006-01-02 15:04:05"))
  2127. fmt.Printf(format, a...)
  2128. }
  2129. func printlnErr(desc, detail string) {
  2130. fmt.Printf("\033[1;31mError: %s. %s\033[0m\n", desc, detail)
  2131. }
  2132. func getCustomRequestMetadataWithRetryPolicy() common.RequestMetadata {
  2133. return common.RequestMetadata{
  2134. RetryPolicy: getCustomRetryPolicy(),
  2135. }
  2136. }
  2137. func getCustomRetryPolicy() *common.RetryPolicy {
  2138. // how many times to do the retry
  2139. attempts := uint(3)
  2140. // retry for all non-200 status code
  2141. retryOnAllNon200ResponseCodes := func(r common.OCIOperationResponse) bool {
  2142. return !(r.Error == nil && 199 < r.Response.HTTPResponse().StatusCode && r.Response.HTTPResponse().StatusCode < 300)
  2143. }
  2144. policy := common.NewRetryPolicyWithOptions(
  2145. // only base off DefaultRetryPolicyWithoutEventualConsistency() if we're not handling eventual consistency
  2146. common.WithConditionalOption(!false, common.ReplaceWithValuesFromRetryPolicy(common.DefaultRetryPolicyWithoutEventualConsistency())),
  2147. common.WithMaximumNumberAttempts(attempts),
  2148. common.WithShouldRetryOperation(retryOnAllNon200ResponseCodes))
  2149. return &policy
  2150. }