main.go 80 KB

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