main.go 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761
  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. "context"
  24. "errors"
  25. "flag"
  26. "fmt"
  27. "io"
  28. "io/ioutil"
  29. "log"
  30. "math/rand"
  31. "net/http"
  32. "net/url"
  33. "os"
  34. "strconv"
  35. "strings"
  36. "text/tabwriter"
  37. "time"
  38. "github.com/oracle/oci-go-sdk/v49/common"
  39. "github.com/oracle/oci-go-sdk/v49/core"
  40. "github.com/oracle/oci-go-sdk/v49/example/helpers"
  41. "github.com/oracle/oci-go-sdk/v49/identity"
  42. "gopkg.in/ini.v1"
  43. )
  44. const (
  45. defConfigFilePath = "./oci-help.ini"
  46. IPsFilePrefix = "IPs"
  47. )
  48. var (
  49. provider common.ConfigurationProvider
  50. computeClient core.ComputeClient
  51. networkClient core.VirtualNetworkClient
  52. ctx context.Context
  53. configFilePath string
  54. sections []*ini.Section
  55. section *ini.Section
  56. config Config
  57. providerName string
  58. proxy string
  59. token string
  60. chat_id string
  61. sendMessageUrl string
  62. EACH bool
  63. )
  64. type Config struct {
  65. AvailabilityDomain string `ini:"availabilityDomain"`
  66. SSH_Public_Key string `ini:"ssh_authorized_key"`
  67. CompartmentID string `ini:"tenancy"`
  68. VcnDisplayName string `ini:"vcnDisplayName"`
  69. SubnetDisplayName string `ini:"subnetDisplayName"`
  70. Shape string `ini:"shape"`
  71. OperatingSystem string `ini:"OperatingSystem"`
  72. OperatingSystemVersion string `ini:"OperatingSystemVersion"`
  73. InstanceDisplayName string `ini:"instanceDisplayName"`
  74. Ocpus float32 `ini:"cpus"`
  75. MemoryInGBs float32 `ini:"memoryInGBs"`
  76. BootVolumeSizeInGBs int64 `ini:"bootVolumeSizeInGBs"`
  77. Sum int32 `ini:"sum"`
  78. Each int32 `ini:"each"`
  79. Retry int32 `ini:"retry"`
  80. CloudInit string `ini:"cloud-init"`
  81. MinTime int32 `ini:"minTime"`
  82. MaxTime int32 `ini:"maxTime"`
  83. }
  84. func main() {
  85. flag.StringVar(&configFilePath, "config", defConfigFilePath, "配置文件路径")
  86. flag.StringVar(&configFilePath, "c", defConfigFilePath, "配置文件路径")
  87. flag.Parse()
  88. cfg, err := ini.Load(configFilePath)
  89. helpers.FatalIfError(err)
  90. defSec := cfg.Section(ini.DefaultSection)
  91. proxy = defSec.Key("proxy").Value()
  92. token = defSec.Key("token").Value()
  93. chat_id = defSec.Key("chat_id").Value()
  94. if defSec.HasKey("EACH") {
  95. EACH, _ = defSec.Key("EACH").Bool()
  96. } else {
  97. EACH = true
  98. }
  99. sendMessageUrl = "https://api.telegram.org/bot" + token + "/sendMessage"
  100. rand.Seed(time.Now().UnixNano())
  101. secs := cfg.Sections()
  102. sections = []*ini.Section{}
  103. for _, sec := range secs {
  104. if len(sec.ParentKeys()) == 0 {
  105. user := sec.Key("user").Value()
  106. fingerprint := sec.Key("fingerprint").Value()
  107. tenancy := sec.Key("tenancy").Value()
  108. region := sec.Key("region").Value()
  109. key_file := sec.Key("key_file").Value()
  110. if user != "" && fingerprint != "" && tenancy != "" && region != "" && key_file != "" {
  111. sections = append(sections, sec)
  112. }
  113. }
  114. }
  115. if len(sections) == 0 {
  116. fmt.Printf("\033[1;31m未找到正确的配置信息, 请参考链接文档配置相关信息。链接: https://github.com/lemoex/oci-help\033[0m\n")
  117. return
  118. }
  119. listOracleAccount()
  120. }
  121. func listOracleAccount() {
  122. if len(sections) == 1 {
  123. section = sections[0]
  124. } else {
  125. fmt.Printf("\n\033[1;32m%s\033[0m\n\n", "欢迎使用甲骨文实例管理工具")
  126. w := new(tabwriter.Writer)
  127. w.Init(os.Stdout, 4, 8, 2, '\t', 0)
  128. fmt.Fprintf(w, "%s\t%s\t%s\t\n", "序号", "账号", "区域")
  129. for i, section := range sections {
  130. fmt.Fprintf(w, "%d\t%s\t%s\t\n", i+1, section.Name(), section.Key("region").Value())
  131. }
  132. w.Flush()
  133. fmt.Printf("\n")
  134. var input string
  135. var index int
  136. for {
  137. fmt.Print("请输入账号对应的序号进入相关操作: ")
  138. _, err := fmt.Scanln(&input)
  139. if err != nil {
  140. return
  141. }
  142. if strings.EqualFold(input, "oci") {
  143. multiBatchLaunchInstances()
  144. listOracleAccount()
  145. return
  146. } else if strings.EqualFold(input, "ip") {
  147. multiBatchListInstancesIp()
  148. listOracleAccount()
  149. return
  150. }
  151. index, _ = strconv.Atoi(input)
  152. if 0 < index && index <= len(sections) {
  153. break
  154. } else {
  155. index = 0
  156. input = ""
  157. fmt.Printf("\033[1;31m错误! 请输入正确的序号\033[0m\n")
  158. }
  159. }
  160. section = sections[index-1]
  161. }
  162. var err error
  163. ctx = context.Background()
  164. provider, err = getProvider(configFilePath, section.Name(), "")
  165. helpers.FatalIfError(err)
  166. computeClient, err = core.NewComputeClientWithConfigurationProvider(provider)
  167. helpers.FatalIfError(err)
  168. setProxyOrNot(&computeClient.BaseClient)
  169. networkClient, err = core.NewVirtualNetworkClientWithConfigurationProvider(provider)
  170. helpers.FatalIfError(err)
  171. setProxyOrNot(&networkClient.BaseClient)
  172. showMainMenu()
  173. }
  174. func showMainMenu() {
  175. fmt.Printf("\n\033[1;32m欢迎使用甲骨文实例管理工具\033[0m \n(当前账号: %s)\n\n", section.Name())
  176. fmt.Printf("\033[1;36m%s\033[0m %s\n", "1.", "查看实例")
  177. fmt.Printf("\033[1;36m%s\033[0m %s\n", "2.", "创建实例")
  178. fmt.Print("\n请输入序号进入相关操作: ")
  179. var input string
  180. var num int
  181. fmt.Scanln(&input)
  182. if strings.EqualFold(input, "oci") {
  183. batchLaunchInstances(section, section.ChildSections())
  184. showMainMenu()
  185. return
  186. } else if strings.EqualFold(input, "ip") {
  187. batchListInstancesIp(section)
  188. showMainMenu()
  189. return
  190. }
  191. num, _ = strconv.Atoi(input)
  192. switch num {
  193. case 1:
  194. listInstances()
  195. case 2:
  196. listLaunchInstanceTemplates()
  197. default:
  198. if len(sections) > 1 {
  199. listOracleAccount()
  200. }
  201. }
  202. }
  203. func listLaunchInstanceTemplates() {
  204. childSections := section.ChildSections()
  205. if len(childSections) == 0 {
  206. fmt.Printf("\033[1;31m未找到实例模版, 回车返回上一级菜单.\033[0m")
  207. fmt.Scanln()
  208. showMainMenu()
  209. return
  210. }
  211. for {
  212. fmt.Printf("\n\033[1;32m%s\033[0m\n\n", "选择对应的实例模版开始创建实例")
  213. w := new(tabwriter.Writer)
  214. w.Init(os.Stdout, 4, 8, 2, '\t', 0)
  215. fmt.Fprintf(w, "%s\t%s\t%s\t\n", "序号", "名称", "配置")
  216. for i, child := range childSections {
  217. fmt.Fprintf(w, "%d\t%s\t%s\t\n", i+1, child.Name(), child.Key("shape").Value())
  218. }
  219. w.Flush()
  220. fmt.Printf("\n")
  221. var input string
  222. var index int
  223. for {
  224. fmt.Print("请输入需要创建的实例的序号: ")
  225. _, err := fmt.Scanln(&input)
  226. if err != nil {
  227. showMainMenu()
  228. return
  229. }
  230. index, _ = strconv.Atoi(input)
  231. if 0 < index && index <= len(childSections) {
  232. break
  233. } else {
  234. input = ""
  235. index = 0
  236. fmt.Printf("\033[1;31m错误! 请输入正确的序号\033[0m\n")
  237. }
  238. }
  239. childSection := childSections[index-1]
  240. // 获取可用性域
  241. availabilityDomains, err := ListAvailabilityDomains()
  242. if err != nil {
  243. fmt.Printf("\033[1;31m获取可用性域失败.\033[0m %s\n", err.Error())
  244. continue
  245. }
  246. providerName = childSection.Name()
  247. config = Config{}
  248. err = childSection.MapTo(&config)
  249. if err != nil {
  250. fmt.Printf("\033[1;31m解析实例参数失败.\033[0m %s\n", err.Error())
  251. continue
  252. }
  253. LaunchInstances(availabilityDomains)
  254. }
  255. }
  256. func listInstances() {
  257. fmt.Println("正在获取实例数据...")
  258. instances, err := ListInstances(ctx, computeClient)
  259. if err != nil {
  260. fmt.Printf("\033[1;31m获取失败, 回车返回上一级菜单.\033[0m")
  261. fmt.Scanln()
  262. showMainMenu()
  263. return
  264. }
  265. if len(instances) == 0 {
  266. fmt.Printf("\033[1;32m实例为空, 回车返回上一级菜单.\033[0m")
  267. fmt.Scanln()
  268. showMainMenu()
  269. return
  270. }
  271. fmt.Printf("\n\033[1;32m实例信息\033[0m \n(当前账号: %s)\n\n", section.Name())
  272. w := new(tabwriter.Writer)
  273. w.Init(os.Stdout, 4, 8, 1, '\t', 0)
  274. fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", "序号", "名称", "状态  ", "配置")
  275. //fmt.Printf("%-5s %-28s %-18s %-20s\n", "序号", "名称", "公共IP", "配置")
  276. for i, ins := range instances {
  277. // 获取实例公共IP
  278. /*
  279. var strIps string
  280. ips, err := getInstancePublicIps(ctx, computeClient, networkClient, ins.Id)
  281. if err != nil {
  282. strIps = err.Error()
  283. } else {
  284. strIps = strings.Join(ips, ",")
  285. }
  286. */
  287. //fmt.Printf("%-7d %-30s %-20s %-20s\n", i+1, *ins.DisplayName, strIps, *ins.Shape)
  288. fmt.Fprintf(w, "%d\t%s\t%s\t%s\t\n", i+1, *ins.DisplayName, getInstanceState(ins.LifecycleState), *ins.Shape)
  289. }
  290. w.Flush()
  291. fmt.Printf("\n")
  292. var input string
  293. var index int
  294. for {
  295. fmt.Print("请输入序号查看实例详细信息: ")
  296. _, err := fmt.Scanln(&input)
  297. if err != nil {
  298. showMainMenu()
  299. return
  300. }
  301. index, _ = strconv.Atoi(input)
  302. if 0 < index && index <= len(instances) {
  303. break
  304. } else {
  305. input = ""
  306. index = 0
  307. fmt.Printf("\033[1;31m错误! 请输入正确的序号\033[0m\n")
  308. }
  309. }
  310. instanceDetails(instances[index-1].Id)
  311. }
  312. func instanceDetails(instanceId *string) {
  313. for {
  314. fmt.Println("正在获取实例详细信息...")
  315. instance, err := getInstance(instanceId)
  316. if err != nil {
  317. fmt.Printf("\033[1;31m获取实例详细信息失败, 回车返回上一级菜单.\033[0m")
  318. fmt.Scanln()
  319. listInstances()
  320. return
  321. }
  322. vnics, err := getInstanceVnics(instanceId)
  323. if err != nil {
  324. fmt.Printf("\033[1;31m获取实例VNIC失败, 回车返回上一级菜单.\033[0m")
  325. fmt.Scanln()
  326. listInstances()
  327. return
  328. }
  329. var publicIps = make([]string, 0)
  330. var strPublicIps string
  331. if err != nil {
  332. strPublicIps = err.Error()
  333. } else {
  334. for _, vnic := range vnics {
  335. if vnic.PublicIp != nil {
  336. publicIps = append(publicIps, *vnic.PublicIp)
  337. }
  338. }
  339. strPublicIps = strings.Join(publicIps, ",")
  340. }
  341. fmt.Printf("\n\033[1;32m实例详细信息\033[0m \n(当前账号: %s)\n\n", section.Name())
  342. fmt.Println("--------------------")
  343. fmt.Printf("名称: %s\n", *instance.DisplayName)
  344. fmt.Printf("状态: %s\n", getInstanceState(instance.LifecycleState))
  345. fmt.Printf("公共IP: %s\n", strPublicIps)
  346. fmt.Printf("可用性域: %s\n", *instance.AvailabilityDomain)
  347. fmt.Printf("配置: %s\n", *instance.Shape)
  348. fmt.Printf("OCPU计数: %g\n", *instance.ShapeConfig.Ocpus)
  349. fmt.Printf("网络带宽(Gbps): %g\n", *instance.ShapeConfig.NetworkingBandwidthInGbps)
  350. fmt.Printf("内存(GB): %g\n", *instance.ShapeConfig.MemoryInGBs)
  351. fmt.Println("--------------------")
  352. fmt.Printf("\n\033[1;32m1: %s 2: %s 3: %s 4: %s 5: %s\033[0m\n", "启动", "停止", "重启", "终止", "更换公共IP")
  353. var input string
  354. var num int
  355. fmt.Print("\n请输入需要执行操作的序号: ")
  356. fmt.Scanln(&input)
  357. num, _ = strconv.Atoi(input)
  358. switch num {
  359. case 1:
  360. _, err := instanceAction(instance.Id, core.InstanceActionActionStart)
  361. if err != nil {
  362. fmt.Printf("\033[1;31m启动实例失败.\033[0m %s\n", err.Error())
  363. } else {
  364. fmt.Printf("\033[1;32m正在启动实例, 请稍后查看实例状态\033[0m\n")
  365. }
  366. time.Sleep(3 * time.Second)
  367. case 2:
  368. _, err := instanceAction(instance.Id, core.InstanceActionActionSoftstop)
  369. if err != nil {
  370. fmt.Printf("\033[1;31m停止实例失败.\033[0m %s\n", err.Error())
  371. } else {
  372. fmt.Printf("\033[1;32m正在停止实例, 请稍后查看实例状态\033[0m\n")
  373. }
  374. time.Sleep(3 * time.Second)
  375. case 3:
  376. _, err := instanceAction(instance.Id, core.InstanceActionActionSoftreset)
  377. if err != nil {
  378. fmt.Printf("\033[1;31m重启实例失败.\033[0m %s\n", err.Error())
  379. } else {
  380. fmt.Printf("\033[1;32m正在重启实例, 请稍后查看实例状态\033[0m\n")
  381. }
  382. time.Sleep(3 * time.Second)
  383. case 4:
  384. fmt.Printf("确定终止实例?(输入 y 并回车): ")
  385. var input string
  386. fmt.Scanln(&input)
  387. if strings.EqualFold(input, "y") {
  388. err := terminateInstance(instance.Id)
  389. if err != nil {
  390. fmt.Printf("\033[1;31m终止实例失败.\033[0m %s\n", err.Error())
  391. } else {
  392. fmt.Printf("\033[1;32m正在终止实例, 请稍后查看实例状态\033[0m\n")
  393. }
  394. time.Sleep(3 * time.Second)
  395. }
  396. case 5:
  397. if len(vnics) == 0 {
  398. fmt.Printf("\033[1;31m实例已终止或获取实例VNIC失败,请稍后重试.\033[0m\n")
  399. break
  400. }
  401. fmt.Printf("将删除当前公共IP并创建一个新的公共IP。确定更换实例公共IP?(输入 y 并回车): ")
  402. var input string
  403. fmt.Scanln(&input)
  404. if strings.EqualFold(input, "y") {
  405. publicIp, err := changePublicIp(vnics)
  406. if err != nil {
  407. fmt.Printf("\033[1;31m更换实例公共IP失败.\033[0m %s\n", err.Error())
  408. } else {
  409. fmt.Printf("\033[1;32m更换实例公共IP成功, 实例公共IP: \033[0m%s\n", *publicIp.IpAddress)
  410. }
  411. time.Sleep(3 * time.Second)
  412. }
  413. default:
  414. listInstances()
  415. return
  416. }
  417. }
  418. }
  419. func getInstance(instanceId *string) (core.Instance, error) {
  420. req := core.GetInstanceRequest{
  421. InstanceId: instanceId,
  422. }
  423. resp, err := computeClient.GetInstance(ctx, req)
  424. return resp.Instance, err
  425. }
  426. func instanceAction(instanceId *string, action core.InstanceActionActionEnum) (ins core.Instance, err error) {
  427. req := core.InstanceActionRequest{
  428. InstanceId: instanceId,
  429. Action: action,
  430. }
  431. resp, err := computeClient.InstanceAction(ctx, req)
  432. ins = resp.Instance
  433. return
  434. }
  435. func changePublicIp(vnics []core.Vnic) (publicIp core.PublicIp, err error) {
  436. var vnic core.Vnic
  437. for _, v := range vnics {
  438. if *v.IsPrimary {
  439. vnic = v
  440. }
  441. }
  442. var privateIps []core.PrivateIp
  443. privateIps, err = getPrivateIps(vnic.Id)
  444. if err != nil {
  445. return
  446. }
  447. var privateIp core.PrivateIp
  448. for _, p := range privateIps {
  449. if *p.IsPrimary {
  450. privateIp = p
  451. }
  452. }
  453. publicIp, err = getPublicIp(privateIp.Id)
  454. if err != nil {
  455. fmt.Println(err.Error())
  456. }
  457. _, err = deletePublicIp(publicIp.Id)
  458. if err != nil {
  459. fmt.Println(err.Error())
  460. }
  461. time.Sleep(3 * time.Second)
  462. publicIp, err = createPublicIp(privateIp.Id)
  463. return
  464. }
  465. func getInstanceVnics(instanceId *string) (vnics []core.Vnic, err error) {
  466. vnicAttachments, err := ListVnicAttachments(ctx, computeClient, instanceId)
  467. if err != nil {
  468. return
  469. }
  470. for _, vnicAttachment := range vnicAttachments {
  471. vnic, vnicErr := GetVnic(ctx, networkClient, vnicAttachment.VnicId)
  472. if vnicErr != nil {
  473. printf("GetVnic error: %s\n", vnicErr.Error())
  474. continue
  475. }
  476. vnics = append(vnics, vnic)
  477. }
  478. return
  479. }
  480. // 更新指定的VNIC
  481. func updateVnic(vnicId *string) (core.Vnic, error) {
  482. req := core.UpdateVnicRequest{
  483. VnicId: vnicId,
  484. UpdateVnicDetails: core.UpdateVnicDetails{SkipSourceDestCheck: common.Bool(true)},
  485. }
  486. resp, err := networkClient.UpdateVnic(ctx, req)
  487. return resp.Vnic, err
  488. }
  489. // 获取指定VNIC的私有IP
  490. func getPrivateIps(vnicId *string) ([]core.PrivateIp, error) {
  491. req := core.ListPrivateIpsRequest{
  492. VnicId: vnicId,
  493. }
  494. resp, err := networkClient.ListPrivateIps(ctx, req)
  495. return resp.Items, err
  496. }
  497. // 获取分配给指定私有IP的公共IP
  498. func getPublicIp(privateIpId *string) (core.PublicIp, error) {
  499. req := core.GetPublicIpByPrivateIpIdRequest{
  500. GetPublicIpByPrivateIpIdDetails: core.GetPublicIpByPrivateIpIdDetails{PrivateIpId: privateIpId},
  501. }
  502. resp, err := networkClient.GetPublicIpByPrivateIpId(ctx, req)
  503. return resp.PublicIp, err
  504. }
  505. // 删除公共IP
  506. // 取消分配并删除指定公共IP(临时或保留)
  507. // 如果仅需要取消分配保留的公共IP并将保留的公共IP返回到保留公共IP池,请使用updatePublicIp方法。
  508. func deletePublicIp(publicIpId *string) (core.DeletePublicIpResponse, error) {
  509. req := core.DeletePublicIpRequest{PublicIpId: publicIpId}
  510. return networkClient.DeletePublicIp(ctx, req)
  511. }
  512. // 创建公共IP
  513. // 通过Lifetime指定创建临时公共IP还是保留公共IP。
  514. // 创建临时公共IP,必须指定privateIpId,将临时公共IP分配给指定私有IP。
  515. // 创建保留公共IP,可以不指定privateIpId。稍后可以使用updatePublicIp方法分配给私有IP。
  516. func createPublicIp(privateIpId *string) (core.PublicIp, error) {
  517. var publicIp core.PublicIp
  518. var compartmentId string
  519. compartmentId, err := provider.TenancyOCID()
  520. if err != nil {
  521. return publicIp, err
  522. }
  523. req := core.CreatePublicIpRequest{
  524. CreatePublicIpDetails: core.CreatePublicIpDetails{
  525. CompartmentId: common.String(compartmentId),
  526. Lifetime: core.CreatePublicIpDetailsLifetimeEphemeral,
  527. PrivateIpId: privateIpId,
  528. },
  529. }
  530. resp, err := networkClient.CreatePublicIp(ctx, req)
  531. publicIp = resp.PublicIp
  532. return publicIp, err
  533. }
  534. // 更新保留公共IP
  535. // 1. 将保留的公共IP分配给指定的私有IP。如果该公共IP已经分配给私有IP,会取消分配,然后重新分配给指定的私有IP。
  536. // 2. PrivateIpId设置为空字符串,公共IP取消分配到关联的私有IP。
  537. func updatePublicIp(publicIpId *string, privateIpId *string) (core.PublicIp, error) {
  538. req := core.UpdatePublicIpRequest{
  539. PublicIpId: publicIpId,
  540. UpdatePublicIpDetails: core.UpdatePublicIpDetails{
  541. PrivateIpId: privateIpId,
  542. },
  543. }
  544. resp, err := networkClient.UpdatePublicIp(ctx, req)
  545. return resp.PublicIp, err
  546. }
  547. func multiBatchLaunchInstances() {
  548. for _, sec := range sections {
  549. childSections := sec.ChildSections()
  550. if len(childSections) > 0 {
  551. var err error
  552. ctx = context.Background()
  553. provider, err = getProvider(configFilePath, sec.Name(), "")
  554. if err != nil {
  555. fmt.Println(err)
  556. return
  557. }
  558. computeClient, err = core.NewComputeClientWithConfigurationProvider(provider)
  559. if err != nil {
  560. fmt.Println(err)
  561. return
  562. }
  563. setProxyOrNot(&computeClient.BaseClient)
  564. networkClient, err = core.NewVirtualNetworkClientWithConfigurationProvider(provider)
  565. if err != nil {
  566. fmt.Println(err)
  567. return
  568. }
  569. setProxyOrNot(&networkClient.BaseClient)
  570. batchLaunchInstances(sec, childSections)
  571. }
  572. }
  573. }
  574. func batchLaunchInstances(sec *ini.Section, childSections []*ini.Section) {
  575. if len(childSections) == 0 {
  576. return
  577. }
  578. // 获取可用性域
  579. AvailabilityDomains, err := ListAvailabilityDomains()
  580. printf("\033[1;36m[%s] 开始创建\033[0m\n", sec.Name())
  581. var SUM, NUM int32 = 0, 0
  582. sendMessage(sec.Name(), "开始创建")
  583. if err != nil {
  584. fmt.Println(err)
  585. return
  586. }
  587. for _, child := range childSections {
  588. providerName = child.Name()
  589. config = Config{}
  590. err := child.MapTo(&config)
  591. if err != nil {
  592. fmt.Println(err)
  593. return
  594. }
  595. sum, num := LaunchInstances(AvailabilityDomains)
  596. SUM = SUM + sum
  597. NUM = NUM + num
  598. }
  599. printf("\033[1;36m[%s] 结束创建。创建实例总数: %d, 成功 %d , 失败 %d\033[0m\n", sec.Name(), SUM, NUM, SUM-NUM)
  600. text := fmt.Sprintf("结束创建。创建实例总数: %d, 成功 %d , 失败 %d", SUM, NUM, SUM-NUM)
  601. sendMessage(sec.Name(), text)
  602. }
  603. // 返回值 sum: 创建实例总数; num: 创建成功的个数
  604. func LaunchInstances(ads []identity.AvailabilityDomain) (sum, num int32) {
  605. /* 创建实例的几种情况
  606. * 1. 设置了 availabilityDomain 参数,即在设置的可用性域中创建 sum 个实例。
  607. * 2. 没有设置 availabilityDomain 但是设置了 each 参数。即在获取的每个可用性域中创建 each 个实例,创建的实例总数 sum = each * adCount。
  608. * 3. 没有设置 availabilityDomain 且没有设置 each 参数,即在获取到的可用性域中创建的实例总数为 sum。
  609. */
  610. //可用性域数量
  611. var adCount int32 = int32(len(ads))
  612. adName := common.String(config.AvailabilityDomain)
  613. each := config.Each
  614. sum = config.Sum
  615. // 没有设置可用性域并且没有设置each时,才有用。
  616. var usableAds = make([]identity.AvailabilityDomain, 0)
  617. //可用性域不固定,即没有提供 availabilityDomain 参数
  618. var AD_NOT_FIXED bool = false
  619. var EACH_AD = false
  620. if adName == nil || *adName == "" {
  621. AD_NOT_FIXED = true
  622. if each > 0 {
  623. EACH_AD = true
  624. sum = each * adCount
  625. } else {
  626. EACH_AD = false
  627. usableAds = ads
  628. }
  629. }
  630. name := config.InstanceDisplayName
  631. if name == "" {
  632. name = time.Now().Format("instance-20060102-1504")
  633. }
  634. displayName := common.String(name)
  635. if sum > 1 {
  636. displayName = common.String(name + "-1")
  637. }
  638. // create the launch instance request
  639. request := core.LaunchInstanceRequest{}
  640. request.CompartmentId = common.String(config.CompartmentID)
  641. request.DisplayName = displayName
  642. // create a subnet or get the one already created
  643. subnet, err := CreateOrGetNetworkInfrastructure(ctx, networkClient)
  644. if err != nil {
  645. fmt.Println(err)
  646. return
  647. }
  648. printf("获取子网: %s\n", *subnet.DisplayName)
  649. request.CreateVnicDetails = &core.CreateVnicDetails{SubnetId: subnet.Id}
  650. // Get a image.
  651. image, err := GetImage(ctx, computeClient)
  652. if err != nil {
  653. fmt.Println(err)
  654. return
  655. }
  656. printf("获取系统: %s\n", *image.DisplayName)
  657. sd := core.InstanceSourceViaImageDetails{}
  658. sd.ImageId = image.Id
  659. if config.BootVolumeSizeInGBs > 0 {
  660. sd.BootVolumeSizeInGBs = common.Int64(config.BootVolumeSizeInGBs)
  661. }
  662. request.SourceDetails = sd
  663. request.IsPvEncryptionInTransitEnabled = common.Bool(true)
  664. request.Shape = common.String(config.Shape)
  665. if config.Ocpus > 0 && config.MemoryInGBs > 0 {
  666. request.ShapeConfig = &core.LaunchInstanceShapeConfigDetails{
  667. Ocpus: common.Float32(config.Ocpus),
  668. MemoryInGBs: common.Float32(config.MemoryInGBs),
  669. }
  670. }
  671. metaData := map[string]string{}
  672. metaData["ssh_authorized_keys"] = config.SSH_Public_Key
  673. if config.CloudInit != "" {
  674. metaData["user_data"] = config.CloudInit
  675. }
  676. request.Metadata = metaData
  677. printf("\033[1;36m[%s] 开始创建...\033[0m\n", providerName)
  678. if EACH {
  679. sendMessage(providerName, "开始尝试创建实例...")
  680. }
  681. minTime := config.MinTime
  682. maxTime := config.MaxTime
  683. SKIP_RETRY_MAP := make(map[int32]bool)
  684. var usableAdsTemp = make([]identity.AvailabilityDomain, 0)
  685. retry := config.Retry // 重试次数
  686. var failTimes int32 = 0 // 失败次数
  687. // 记录尝试创建实例的次数
  688. var runTimes int32 = 0
  689. var adIndex int32 = 0 // 当前可用性域下标
  690. var pos int32 = 0 // for 循环次数
  691. var SUCCESS = false // 创建是否成功
  692. for pos < sum {
  693. if AD_NOT_FIXED {
  694. if EACH_AD {
  695. if pos%each == 0 && failTimes == 0 {
  696. adName = ads[adIndex].Name
  697. adIndex++
  698. }
  699. } else {
  700. if SUCCESS {
  701. adIndex = 0
  702. }
  703. if adIndex >= adCount {
  704. adIndex = 0
  705. }
  706. //adName = ads[adIndex].Name
  707. adName = usableAds[adIndex].Name
  708. adIndex++
  709. }
  710. }
  711. runTimes++
  712. printf("\033[1;36m[%s] 正在尝试创建第 %d 个实例, AD: %s\033[0m\n", providerName, pos+1, *adName)
  713. printf("\033[1;36m[%s] 当前尝试次数: %d \033[0m\n", providerName, runTimes)
  714. request.AvailabilityDomain = adName
  715. createResp, err := computeClient.LaunchInstance(ctx, request)
  716. if err == nil {
  717. // 创建实例成功
  718. SUCCESS = true
  719. num++ //成功个数+1
  720. // 获取实例公共IP
  721. ips, err := getInstancePublicIps(ctx, computeClient, networkClient, createResp.Instance.Id)
  722. var strIps string
  723. if err != nil {
  724. strIps = err.Error()
  725. } else {
  726. strIps = strings.Join(ips, ",")
  727. }
  728. printf("\033[1;32m[%s] 第 %d 个实例创建成功. 实例名称: %s, 公网IP: %s\033[0m\n", providerName, pos+1, *createResp.Instance.DisplayName, strIps)
  729. if EACH {
  730. sendMessage(providerName, fmt.Sprintf("经过 %d 次尝试, 第%d个实例创建成功🎉\n实例名称: %s\n公网IP: %s", runTimes, pos+1, *createResp.Instance.DisplayName, strIps))
  731. }
  732. sleepRandomSecond(minTime, maxTime)
  733. displayName = common.String(fmt.Sprintf("%s-%d", name, pos+1))
  734. request.DisplayName = displayName
  735. } else {
  736. // 创建实例失败
  737. SUCCESS = false
  738. // 错误信息
  739. errInfo := err.Error()
  740. // 是否跳过重试
  741. SKIP_RETRY := false
  742. //isRetryable := common.IsErrorRetryableByDefault(err)
  743. //isNetErr := common.IsNetworkError(err)
  744. servErr, isServErr := common.IsServiceError(err)
  745. // API Errors: https://docs.cloud.oracle.com/Content/API/References/apierrors.htm
  746. if isServErr && (400 <= servErr.GetHTTPStatusCode() && servErr.GetHTTPStatusCode() <= 405) ||
  747. (servErr.GetHTTPStatusCode() == 409 && !strings.EqualFold(servErr.GetCode(), "IncorrectState")) ||
  748. servErr.GetHTTPStatusCode() == 412 || servErr.GetHTTPStatusCode() == 413 || servErr.GetHTTPStatusCode() == 422 ||
  749. servErr.GetHTTPStatusCode() == 431 || servErr.GetHTTPStatusCode() == 501 {
  750. // 不可重试
  751. if isServErr {
  752. errInfo = servErr.GetMessage()
  753. }
  754. printf("\033[1;31m[%s] 创建失败, Error: \033[0m%s\n", providerName, errInfo)
  755. if EACH {
  756. sendMessage(providerName, "创建失败,Error: "+errInfo)
  757. }
  758. SKIP_RETRY = true
  759. if AD_NOT_FIXED && !EACH_AD {
  760. SKIP_RETRY_MAP[adIndex-1] = true
  761. }
  762. } else {
  763. // 可重试
  764. if isServErr {
  765. errInfo = servErr.GetMessage()
  766. }
  767. printf("\033[1;31m[%s] 创建失败, Error: \033[0m%s\n", providerName, errInfo)
  768. SKIP_RETRY = false
  769. if AD_NOT_FIXED && !EACH_AD {
  770. SKIP_RETRY_MAP[adIndex-1] = false
  771. }
  772. }
  773. sleepRandomSecond(minTime, maxTime)
  774. if AD_NOT_FIXED {
  775. if !EACH_AD {
  776. if adIndex < adCount {
  777. // 没有设置可用性域,且没有设置each。即在获取到的每个可用性域里尝试创建。当前使用的可用性域不是最后一个,继续尝试。
  778. continue
  779. } else {
  780. // 当前使用的可用性域是最后一个,判断失败次数是否达到重试次数,未达到重试次数继续尝试。
  781. failTimes++
  782. for index, skip := range SKIP_RETRY_MAP {
  783. if !skip {
  784. usableAdsTemp = append(usableAdsTemp, usableAds[index])
  785. }
  786. }
  787. // 重新设置 usableAds
  788. usableAds = usableAdsTemp
  789. adCount = int32(len(usableAds))
  790. // 重置变量
  791. usableAdsTemp = nil
  792. for k := range SKIP_RETRY_MAP {
  793. delete(SKIP_RETRY_MAP, k)
  794. }
  795. // 判断是否需要重试
  796. if (retry < 0 || failTimes <= retry) && adCount > 0 {
  797. continue
  798. }
  799. }
  800. adIndex = 0
  801. } else {
  802. // 没有设置可用性域,且设置了each,即在每个域创建each个实例。判断失败次数继续尝试。
  803. failTimes++
  804. if (retry < 0 || failTimes <= retry) && !SKIP_RETRY {
  805. continue
  806. }
  807. }
  808. } else {
  809. //设置了可用性域,判断是否需要重试
  810. failTimes++
  811. if (retry < 0 || failTimes <= retry) && !SKIP_RETRY {
  812. continue
  813. }
  814. }
  815. }
  816. // 重置变量
  817. usableAds = ads
  818. adCount = int32(len(usableAds))
  819. usableAdsTemp = nil
  820. for k := range SKIP_RETRY_MAP {
  821. delete(SKIP_RETRY_MAP, k)
  822. }
  823. // 成功或者失败次数达到重试次数,重置失败次数为0
  824. failTimes = 0
  825. // 重置尝试创建实例次数
  826. runTimes = 0
  827. // for 循环次数+1
  828. pos++
  829. }
  830. return
  831. }
  832. func sleepRandomSecond(min, max int32) {
  833. var second int32
  834. if min <= 0 || max <= 0 {
  835. second = 1
  836. } else if min >= max {
  837. second = max
  838. } else {
  839. second = rand.Int31n(max-min) + min
  840. }
  841. printf("Sleep %d Second...\n", second)
  842. time.Sleep(time.Duration(second) * time.Second)
  843. }
  844. func multiBatchListInstancesIp() {
  845. IPsFilePath := IPsFilePrefix + "-" + time.Now().Format("2006-01-02-150405.txt")
  846. _, err := os.Stat(IPsFilePath)
  847. if err != nil && os.IsNotExist(err) {
  848. os.Create(IPsFilePath)
  849. }
  850. fmt.Printf("正在获取所有实例公共IP地址...\n")
  851. for _, sec := range sections {
  852. var err error
  853. ctx = context.Background()
  854. provider, err = getProvider(configFilePath, sec.Name(), "")
  855. if err != nil {
  856. fmt.Println(err)
  857. return
  858. }
  859. computeClient, err = core.NewComputeClientWithConfigurationProvider(provider)
  860. if err != nil {
  861. fmt.Println(err)
  862. return
  863. }
  864. setProxyOrNot(&computeClient.BaseClient)
  865. networkClient, err = core.NewVirtualNetworkClientWithConfigurationProvider(provider)
  866. if err != nil {
  867. fmt.Println(err)
  868. return
  869. }
  870. setProxyOrNot(&networkClient.BaseClient)
  871. ListInstancesIPs(IPsFilePath, sec.Name())
  872. }
  873. fmt.Printf("获取所有实例公共IP地址完成,请查看文件 %s\n", IPsFilePath)
  874. }
  875. func batchListInstancesIp(sec *ini.Section) {
  876. IPsFilePath := IPsFilePrefix + "-" + time.Now().Format("2006-01-02-150405.txt")
  877. _, err := os.Stat(IPsFilePath)
  878. if err != nil && os.IsNotExist(err) {
  879. os.Create(IPsFilePath)
  880. }
  881. fmt.Printf("正在获取所有实例公共IP地址...\n")
  882. ListInstancesIPs(IPsFilePath, sec.Name())
  883. fmt.Printf("获取所有实例IP地址完成,请查看文件 %s\n", IPsFilePath)
  884. }
  885. func ListInstancesIPs(filePath string, sectionName string) {
  886. vnicAttachments, err := ListVnicAttachments(ctx, computeClient, nil)
  887. if err != nil {
  888. fmt.Printf("ListVnicAttachments Error: %s\n", err.Error())
  889. return
  890. }
  891. file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
  892. if err != nil {
  893. fmt.Printf("打开文件失败, Error: %s\n", err.Error())
  894. return
  895. }
  896. _, err = io.WriteString(file, "["+sectionName+"]\n")
  897. if err != nil {
  898. fmt.Printf("%s\n", err.Error())
  899. }
  900. for _, vnicAttachment := range vnicAttachments {
  901. vnic, err := GetVnic(ctx, networkClient, vnicAttachment.VnicId)
  902. if err != nil {
  903. fmt.Printf("IP地址获取失败, %s\n", err.Error())
  904. continue
  905. }
  906. fmt.Printf("[%s] 实例: %s, IP: %s\n", sectionName, *vnic.DisplayName, *vnic.PublicIp)
  907. _, err = io.WriteString(file, "实例: "+*vnic.DisplayName+", IP: "+*vnic.PublicIp+"\n")
  908. if err != nil {
  909. fmt.Printf("写入文件失败, Error: %s\n", err.Error())
  910. }
  911. }
  912. _, err = io.WriteString(file, "\n")
  913. if err != nil {
  914. fmt.Printf("%s\n", err.Error())
  915. }
  916. }
  917. // ExampleLaunchInstance does create an instance
  918. // NOTE: launch instance will create a new instance and VCN. please make sure delete the instance
  919. // after execute this sample code, otherwise, you will be charged for the running instance
  920. func ExampleLaunchInstance() {
  921. c, err := core.NewComputeClientWithConfigurationProvider(provider)
  922. helpers.FatalIfError(err)
  923. networkClient, err := core.NewVirtualNetworkClientWithConfigurationProvider(provider)
  924. helpers.FatalIfError(err)
  925. ctx := context.Background()
  926. // create the launch instance request
  927. request := core.LaunchInstanceRequest{}
  928. request.CompartmentId = common.String(config.CompartmentID)
  929. request.DisplayName = common.String(config.InstanceDisplayName)
  930. request.AvailabilityDomain = common.String(config.AvailabilityDomain)
  931. // create a subnet or get the one already created
  932. subnet, err := CreateOrGetNetworkInfrastructure(ctx, networkClient)
  933. helpers.FatalIfError(err)
  934. fmt.Println("subnet created")
  935. request.CreateVnicDetails = &core.CreateVnicDetails{SubnetId: subnet.Id}
  936. // get a image
  937. images, err := listImages(ctx, c)
  938. helpers.FatalIfError(err)
  939. image := images[0]
  940. fmt.Println("list images")
  941. request.SourceDetails = core.InstanceSourceViaImageDetails{
  942. ImageId: image.Id,
  943. BootVolumeSizeInGBs: common.Int64(config.BootVolumeSizeInGBs),
  944. }
  945. // use [config.Shape] to create instance
  946. request.Shape = common.String(config.Shape)
  947. request.ShapeConfig = &core.LaunchInstanceShapeConfigDetails{
  948. Ocpus: common.Float32(config.Ocpus),
  949. MemoryInGBs: common.Float32(config.MemoryInGBs),
  950. }
  951. // add ssh_authorized_keys
  952. //metaData := map[string]string{
  953. // "ssh_authorized_keys": config.SSH_Public_Key,
  954. //}
  955. //request.Metadata = metaData
  956. request.Metadata = map[string]string{"ssh_authorized_keys": config.SSH_Public_Key}
  957. // default retry policy will retry on non-200 response
  958. request.RequestMetadata = helpers.GetRequestMetadataWithDefaultRetryPolicy()
  959. createResp, err := c.LaunchInstance(ctx, request)
  960. helpers.FatalIfError(err)
  961. fmt.Println("launching instance")
  962. // should retry condition check which returns a bool value indicating whether to do retry or not
  963. // it checks the lifecycle status equals to Running or not for this case
  964. shouldRetryFunc := func(r common.OCIOperationResponse) bool {
  965. if converted, ok := r.Response.(core.GetInstanceResponse); ok {
  966. return converted.LifecycleState != core.InstanceLifecycleStateRunning
  967. }
  968. return true
  969. }
  970. // create get instance request with a retry policy which takes a function
  971. // to determine shouldRetry or not
  972. pollingGetRequest := core.GetInstanceRequest{
  973. InstanceId: createResp.Instance.Id,
  974. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
  975. }
  976. instance, pollError := c.GetInstance(ctx, pollingGetRequest)
  977. helpers.FatalIfError(pollError)
  978. fmt.Println("instance launched")
  979. // 创建辅助 VNIC 并将其附加到指定的实例
  980. attachVnicResponse, err := c.AttachVnic(context.Background(), core.AttachVnicRequest{
  981. AttachVnicDetails: core.AttachVnicDetails{
  982. CreateVnicDetails: &core.CreateVnicDetails{
  983. SubnetId: subnet.Id,
  984. AssignPublicIp: common.Bool(true),
  985. },
  986. InstanceId: instance.Id,
  987. },
  988. })
  989. helpers.FatalIfError(err)
  990. fmt.Println("vnic attached")
  991. vnicState := attachVnicResponse.VnicAttachment.LifecycleState
  992. for vnicState != core.VnicAttachmentLifecycleStateAttached {
  993. time.Sleep(15 * time.Second)
  994. getVnicAttachmentRequest, err := c.GetVnicAttachment(context.Background(), core.GetVnicAttachmentRequest{
  995. VnicAttachmentId: attachVnicResponse.Id,
  996. })
  997. helpers.FatalIfError(err)
  998. vnicState = getVnicAttachmentRequest.VnicAttachment.LifecycleState
  999. }
  1000. // 分离并删除指定的辅助 VNIC
  1001. _, err = c.DetachVnic(context.Background(), core.DetachVnicRequest{
  1002. VnicAttachmentId: attachVnicResponse.Id,
  1003. })
  1004. helpers.FatalIfError(err)
  1005. fmt.Println("vnic dettached")
  1006. defer func() {
  1007. terminateInstance(createResp.Id)
  1008. client, clerr := core.NewVirtualNetworkClientWithConfigurationProvider(common.DefaultConfigProvider())
  1009. helpers.FatalIfError(clerr)
  1010. vcnID := subnet.VcnId
  1011. deleteSubnet(ctx, client, subnet.Id)
  1012. deleteVcn(ctx, client, vcnID)
  1013. }()
  1014. // Output:
  1015. // subnet created
  1016. // list images
  1017. // list shapes
  1018. // launching instance
  1019. // instance launched
  1020. // vnic attached
  1021. // vnic dettached
  1022. // terminating instance
  1023. // instance terminated
  1024. // deleteing subnet
  1025. // subnet deleted
  1026. // deleteing VCN
  1027. // VCN deleted
  1028. }
  1029. func getProvider(configPath, profile, privateKeyPassword string) (common.ConfigurationProvider, error) {
  1030. //provider := common.DefaultConfigProvider()
  1031. //provider, err := common.ConfigurationProviderFromFile("./oci-config", "")
  1032. provider, err := common.ConfigurationProviderFromFileWithProfile(configPath, profile, privateKeyPassword)
  1033. return provider, err
  1034. }
  1035. // 创建或获取基础网络设施
  1036. func CreateOrGetNetworkInfrastructure(ctx context.Context, c core.VirtualNetworkClient) (subnet core.Subnet, err error) {
  1037. var vcn core.Vcn
  1038. vcn, err = createOrGetVcn(ctx, c)
  1039. if err != nil {
  1040. return
  1041. }
  1042. var gateway core.InternetGateway
  1043. gateway, err = createOrGetInternetGateway(c, vcn.Id)
  1044. if err != nil {
  1045. return
  1046. }
  1047. _, err = createOrGetRouteTable(c, gateway.Id, vcn.Id)
  1048. if err != nil {
  1049. return
  1050. }
  1051. subnet, err = createOrGetSubnetWithDetails(
  1052. ctx, c, vcn.Id,
  1053. common.String(config.SubnetDisplayName),
  1054. common.String("10.0.0.0/24"),
  1055. common.String("subnetdns"),
  1056. common.String(config.AvailabilityDomain))
  1057. return
  1058. }
  1059. // CreateOrGetSubnetWithDetails either creates a new Virtual Cloud Network (VCN) or get the one already exist
  1060. // with detail info
  1061. func createOrGetSubnetWithDetails(ctx context.Context, c core.VirtualNetworkClient, vcnID *string,
  1062. displayName *string, cidrBlock *string, dnsLabel *string, availableDomain *string) (subnet core.Subnet, err error) {
  1063. var subnets []core.Subnet
  1064. subnets, err = listSubnets(ctx, c, vcnID)
  1065. if err != nil {
  1066. return
  1067. }
  1068. if displayName == nil {
  1069. displayName = common.String(config.SubnetDisplayName)
  1070. }
  1071. if len(subnets) > 0 && *displayName == "" {
  1072. subnet = subnets[0]
  1073. return
  1074. }
  1075. // check if the subnet has already been created
  1076. for _, element := range subnets {
  1077. if *element.DisplayName == *displayName {
  1078. // find the subnet, return it
  1079. subnet = element
  1080. return
  1081. }
  1082. }
  1083. // create a new subnet
  1084. printf("开始创建Subnet(没有可用的Subnet,或指定的Subnet不存在)\n")
  1085. // 子网名称为空,以当前时间为名称创建子网
  1086. if *displayName == "" {
  1087. displayName = common.String(time.Now().Format("subnet-20060102-1504"))
  1088. }
  1089. request := core.CreateSubnetRequest{}
  1090. //request.AvailabilityDomain = availableDomain //省略此属性创建区域性子网(regional subnet),提供此属性创建特定于可用性域的子网。建议创建区域性子网。
  1091. request.CompartmentId = &config.CompartmentID
  1092. request.CidrBlock = cidrBlock
  1093. request.DisplayName = displayName
  1094. request.DnsLabel = dnsLabel
  1095. request.RequestMetadata = helpers.GetRequestMetadataWithDefaultRetryPolicy()
  1096. request.VcnId = vcnID
  1097. var r core.CreateSubnetResponse
  1098. r, err = c.CreateSubnet(ctx, request)
  1099. if err != nil {
  1100. return
  1101. }
  1102. // retry condition check, stop unitl return true
  1103. pollUntilAvailable := func(r common.OCIOperationResponse) bool {
  1104. if converted, ok := r.Response.(core.GetSubnetResponse); ok {
  1105. return converted.LifecycleState != core.SubnetLifecycleStateAvailable
  1106. }
  1107. return true
  1108. }
  1109. pollGetRequest := core.GetSubnetRequest{
  1110. SubnetId: r.Id,
  1111. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(pollUntilAvailable),
  1112. }
  1113. // wait for lifecyle become running
  1114. _, err = c.GetSubnet(ctx, pollGetRequest)
  1115. if err != nil {
  1116. return
  1117. }
  1118. // update the security rules
  1119. getReq := core.GetSecurityListRequest{
  1120. SecurityListId: common.String(r.SecurityListIds[0]),
  1121. }
  1122. var getResp core.GetSecurityListResponse
  1123. getResp, err = c.GetSecurityList(ctx, getReq)
  1124. if err != nil {
  1125. return
  1126. }
  1127. // this security rule allows remote control the instance
  1128. /*portRange := core.PortRange{
  1129. Max: common.Int(1521),
  1130. Min: common.Int(1521),
  1131. }*/
  1132. newRules := append(getResp.IngressSecurityRules, core.IngressSecurityRule{
  1133. //Protocol: common.String("6"), // TCP
  1134. Protocol: common.String("all"), // 允许所有协议
  1135. Source: common.String("0.0.0.0/0"),
  1136. /*TcpOptions: &core.TcpOptions{
  1137. DestinationPortRange: &portRange, // 省略该参数,允许所有目标端口。
  1138. },*/
  1139. })
  1140. updateReq := core.UpdateSecurityListRequest{
  1141. SecurityListId: common.String(r.SecurityListIds[0]),
  1142. }
  1143. updateReq.IngressSecurityRules = newRules
  1144. _, err = c.UpdateSecurityList(ctx, updateReq)
  1145. if err != nil {
  1146. return
  1147. }
  1148. printf("Subnet创建成功: %s\n", *r.Subnet.DisplayName)
  1149. subnet = r.Subnet
  1150. return
  1151. }
  1152. // 列出指定虚拟云网络 (VCN) 中的所有子网,如果该 VCN 不存在会创建 VCN
  1153. func listSubnets(ctx context.Context, c core.VirtualNetworkClient, vcnID *string) (subnets []core.Subnet, err error) {
  1154. request := core.ListSubnetsRequest{
  1155. CompartmentId: &config.CompartmentID,
  1156. VcnId: vcnID,
  1157. }
  1158. var r core.ListSubnetsResponse
  1159. r, err = c.ListSubnets(ctx, request)
  1160. if err != nil {
  1161. return
  1162. }
  1163. subnets = r.Items
  1164. return
  1165. }
  1166. // 创建一个新的虚拟云网络 (VCN) 或获取已经存在的虚拟云网络
  1167. func createOrGetVcn(ctx context.Context, c core.VirtualNetworkClient) (core.Vcn, error) {
  1168. var vcn core.Vcn
  1169. vcnItems, err := listVcns(ctx, c)
  1170. if err != nil {
  1171. return vcn, err
  1172. }
  1173. displayName := common.String(config.VcnDisplayName)
  1174. if len(vcnItems) > 0 && *displayName == "" {
  1175. vcn = vcnItems[0]
  1176. return vcn, err
  1177. }
  1178. for _, element := range vcnItems {
  1179. if *element.DisplayName == config.VcnDisplayName {
  1180. // VCN already created, return it
  1181. vcn = element
  1182. return vcn, err
  1183. }
  1184. }
  1185. // create a new VCN
  1186. printf("开始创建VCN(没有可用的VCN,或指定的VCN不存在)\n")
  1187. if *displayName == "" {
  1188. displayName = common.String(time.Now().Format("vcn-20060102-1504"))
  1189. }
  1190. request := core.CreateVcnRequest{}
  1191. request.CidrBlock = common.String("10.0.0.0/16")
  1192. request.CompartmentId = common.String(config.CompartmentID)
  1193. request.DisplayName = displayName
  1194. request.DnsLabel = common.String("vcndns")
  1195. r, err := c.CreateVcn(ctx, request)
  1196. if err != nil {
  1197. return vcn, err
  1198. }
  1199. printf("VCN创建成功: %s\n", *r.Vcn.DisplayName)
  1200. vcn = r.Vcn
  1201. return vcn, err
  1202. }
  1203. // 列出所有虚拟云网络 (VCN)
  1204. func listVcns(ctx context.Context, c core.VirtualNetworkClient) ([]core.Vcn, error) {
  1205. request := core.ListVcnsRequest{
  1206. CompartmentId: &config.CompartmentID,
  1207. }
  1208. r, err := c.ListVcns(ctx, request)
  1209. if err != nil {
  1210. return nil, err
  1211. }
  1212. return r.Items, err
  1213. }
  1214. // 创建或者获取 Internet 网关
  1215. func createOrGetInternetGateway(c core.VirtualNetworkClient, vcnID *string) (core.InternetGateway, error) {
  1216. //List Gateways
  1217. var gateway core.InternetGateway
  1218. listGWRequest := core.ListInternetGatewaysRequest{
  1219. CompartmentId: &config.CompartmentID,
  1220. VcnId: vcnID,
  1221. }
  1222. listGWRespone, err := c.ListInternetGateways(ctx, listGWRequest)
  1223. if err != nil {
  1224. printf("Internet gateway list error: %s\n", err.Error())
  1225. return gateway, err
  1226. }
  1227. if len(listGWRespone.Items) >= 1 {
  1228. //Gateway with name already exists
  1229. gateway = listGWRespone.Items[0]
  1230. } else {
  1231. //Create new Gateway
  1232. printf("开始创建Internet网关\n")
  1233. enabled := true
  1234. createGWDetails := core.CreateInternetGatewayDetails{
  1235. CompartmentId: &config.CompartmentID,
  1236. IsEnabled: &enabled,
  1237. VcnId: vcnID,
  1238. }
  1239. createGWRequest := core.CreateInternetGatewayRequest{CreateInternetGatewayDetails: createGWDetails}
  1240. createGWResponse, err := c.CreateInternetGateway(ctx, createGWRequest)
  1241. if err != nil {
  1242. printf("Internet gateway create error: %s\n", err.Error())
  1243. return gateway, err
  1244. }
  1245. gateway = createGWResponse.InternetGateway
  1246. printf("Internet网关创建成功: %s\n", *gateway.DisplayName)
  1247. }
  1248. return gateway, err
  1249. }
  1250. // 创建或者获取路由表
  1251. func createOrGetRouteTable(c core.VirtualNetworkClient, gatewayID, VcnID *string) (routeTable core.RouteTable, err error) {
  1252. //List Route Table
  1253. listRTRequest := core.ListRouteTablesRequest{
  1254. CompartmentId: &config.CompartmentID,
  1255. VcnId: VcnID,
  1256. }
  1257. var listRTResponse core.ListRouteTablesResponse
  1258. listRTResponse, err = c.ListRouteTables(ctx, listRTRequest)
  1259. if err != nil {
  1260. printf("Route table list error: %s\n", err.Error())
  1261. return
  1262. }
  1263. cidrRange := "0.0.0.0/0"
  1264. rr := core.RouteRule{
  1265. NetworkEntityId: gatewayID,
  1266. Destination: &cidrRange,
  1267. DestinationType: core.RouteRuleDestinationTypeCidrBlock,
  1268. }
  1269. if len(listRTResponse.Items) >= 1 {
  1270. //Default Route Table found and has at least 1 route rule
  1271. if len(listRTResponse.Items[0].RouteRules) >= 1 {
  1272. routeTable = listRTResponse.Items[0]
  1273. //Default Route table needs route rule adding
  1274. } else {
  1275. printf("路由表未添加规则,开始添加Internet路由规则\n")
  1276. updateRTDetails := core.UpdateRouteTableDetails{
  1277. RouteRules: []core.RouteRule{rr},
  1278. }
  1279. updateRTRequest := core.UpdateRouteTableRequest{
  1280. RtId: listRTResponse.Items[0].Id,
  1281. UpdateRouteTableDetails: updateRTDetails,
  1282. }
  1283. var updateRTResponse core.UpdateRouteTableResponse
  1284. updateRTResponse, err = c.UpdateRouteTable(ctx, updateRTRequest)
  1285. if err != nil {
  1286. printf("Error updating route table: %s\n", err)
  1287. return
  1288. }
  1289. printf("Internet路由规则添加成功\n")
  1290. routeTable = updateRTResponse.RouteTable
  1291. }
  1292. } else {
  1293. //No default route table found
  1294. printf("Error could not find VCN default route table, VCN OCID: %s Could not find route table.\n", *VcnID)
  1295. }
  1296. return
  1297. }
  1298. // 获取符合条件系统镜像中的第一个
  1299. func GetImage(ctx context.Context, c core.ComputeClient) (image core.Image, err error) {
  1300. var images []core.Image
  1301. images, err = listImages(ctx, c)
  1302. if err != nil {
  1303. return
  1304. }
  1305. if len(images) > 0 {
  1306. image = images[0]
  1307. } else {
  1308. err = fmt.Errorf("未找到[%s %s]的镜像, 或该镜像不支持[%s]", config.OperatingSystem, config.OperatingSystemVersion, config.Shape)
  1309. }
  1310. return
  1311. }
  1312. // 列出所有符合条件的系统镜像
  1313. func listImages(ctx context.Context, c core.ComputeClient) ([]core.Image, error) {
  1314. request := core.ListImagesRequest{
  1315. CompartmentId: common.String(config.CompartmentID),
  1316. OperatingSystem: common.String(config.OperatingSystem),
  1317. OperatingSystemVersion: common.String(config.OperatingSystemVersion),
  1318. Shape: common.String(config.Shape),
  1319. }
  1320. r, err := c.ListImages(ctx, request)
  1321. return r.Items, err
  1322. }
  1323. // ListShapes Lists the shapes that can be used to launch an instance within the specified compartment.
  1324. func listShapes(ctx context.Context, c core.ComputeClient, imageID *string) []core.Shape {
  1325. request := core.ListShapesRequest{
  1326. CompartmentId: common.String(config.CompartmentID),
  1327. ImageId: imageID,
  1328. }
  1329. r, err := c.ListShapes(ctx, request)
  1330. helpers.FatalIfError(err)
  1331. if r.Items == nil || len(r.Items) == 0 {
  1332. log.Fatalln("Invalid response from ListShapes")
  1333. }
  1334. return r.Items
  1335. }
  1336. // 列出符合条件的可用性域
  1337. func ListAvailabilityDomains() ([]identity.AvailabilityDomain, error) {
  1338. c, err := identity.NewIdentityClientWithConfigurationProvider(provider)
  1339. if err != nil {
  1340. return nil, err
  1341. }
  1342. setProxyOrNot(&c.BaseClient)
  1343. req := identity.ListAvailabilityDomainsRequest{}
  1344. compartmentID, err := provider.TenancyOCID()
  1345. if err != nil {
  1346. return nil, err
  1347. }
  1348. req.CompartmentId = common.String(compartmentID)
  1349. resp, err := c.ListAvailabilityDomains(context.Background(), req)
  1350. return resp.Items, err
  1351. }
  1352. func ListInstances(ctx context.Context, c core.ComputeClient) ([]core.Instance, error) {
  1353. compartmentID, err := provider.TenancyOCID()
  1354. if err != nil {
  1355. return nil, err
  1356. }
  1357. req := core.ListInstancesRequest{
  1358. CompartmentId: &compartmentID,
  1359. }
  1360. resp, err := c.ListInstances(ctx, req)
  1361. return resp.Items, err
  1362. }
  1363. func ListVnicAttachments(ctx context.Context, c core.ComputeClient, instanceId *string) ([]core.VnicAttachment, error) {
  1364. compartmentID, err := provider.TenancyOCID()
  1365. if err != nil {
  1366. return nil, err
  1367. }
  1368. req := core.ListVnicAttachmentsRequest{CompartmentId: &compartmentID}
  1369. if instanceId != nil && *instanceId != "" {
  1370. req.InstanceId = instanceId
  1371. }
  1372. resp, err := c.ListVnicAttachments(ctx, req)
  1373. return resp.Items, err
  1374. }
  1375. func GetVnic(ctx context.Context, c core.VirtualNetworkClient, vnicID *string) (core.Vnic, error) {
  1376. req := core.GetVnicRequest{VnicId: vnicID}
  1377. resp, err := c.GetVnic(ctx, req)
  1378. if err != nil && resp.RawResponse != nil {
  1379. err = errors.New(resp.RawResponse.Status)
  1380. }
  1381. return resp.Vnic, err
  1382. }
  1383. // 终止实例
  1384. // https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/Instance/TerminateInstance
  1385. func terminateInstance(id *string) error {
  1386. request := core.TerminateInstanceRequest{
  1387. InstanceId: id,
  1388. PreserveBootVolume: common.Bool(false),
  1389. RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
  1390. }
  1391. _, err := computeClient.TerminateInstance(ctx, request)
  1392. return err
  1393. //fmt.Println("terminating instance")
  1394. /*
  1395. // should retry condition check which returns a bool value indicating whether to do retry or not
  1396. // it checks the lifecycle status equals to Terminated or not for this case
  1397. shouldRetryFunc := func(r common.OCIOperationResponse) bool {
  1398. if converted, ok := r.Response.(core.GetInstanceResponse); ok {
  1399. return converted.LifecycleState != core.InstanceLifecycleStateTerminated
  1400. }
  1401. return true
  1402. }
  1403. pollGetRequest := core.GetInstanceRequest{
  1404. InstanceId: id,
  1405. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
  1406. }
  1407. _, pollErr := c.GetInstance(ctx, pollGetRequest)
  1408. helpers.FatalIfError(pollErr)
  1409. fmt.Println("instance terminated")
  1410. */
  1411. }
  1412. // 删除虚拟云网络
  1413. func deleteVcn(ctx context.Context, c core.VirtualNetworkClient, id *string) {
  1414. request := core.DeleteVcnRequest{
  1415. VcnId: id,
  1416. RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
  1417. }
  1418. fmt.Println("deleteing VCN")
  1419. _, err := c.DeleteVcn(ctx, request)
  1420. helpers.FatalIfError(err)
  1421. // should retry condition check which returns a bool value indicating whether to do retry or not
  1422. // it checks the lifecycle status equals to Terminated or not for this case
  1423. shouldRetryFunc := func(r common.OCIOperationResponse) bool {
  1424. if serviceError, ok := common.IsServiceError(r.Error); ok && serviceError.GetHTTPStatusCode() == 404 {
  1425. // resource been deleted, stop retry
  1426. return false
  1427. }
  1428. if converted, ok := r.Response.(core.GetVcnResponse); ok {
  1429. return converted.LifecycleState != core.VcnLifecycleStateTerminated
  1430. }
  1431. return true
  1432. }
  1433. pollGetRequest := core.GetVcnRequest{
  1434. VcnId: id,
  1435. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
  1436. }
  1437. _, pollErr := c.GetVcn(ctx, pollGetRequest)
  1438. if serviceError, ok := common.IsServiceError(pollErr); !ok ||
  1439. (ok && serviceError.GetHTTPStatusCode() != 404) {
  1440. // fail if the error is not service error or
  1441. // if the error is service error and status code not equals to 404
  1442. helpers.FatalIfError(pollErr)
  1443. }
  1444. fmt.Println("VCN deleted")
  1445. }
  1446. // 删除子网
  1447. func deleteSubnet(ctx context.Context, c core.VirtualNetworkClient, id *string) {
  1448. request := core.DeleteSubnetRequest{
  1449. SubnetId: id,
  1450. RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
  1451. }
  1452. _, err := c.DeleteSubnet(context.Background(), request)
  1453. helpers.FatalIfError(err)
  1454. fmt.Println("deleteing subnet")
  1455. // should retry condition check which returns a bool value indicating whether to do retry or not
  1456. // it checks the lifecycle status equals to Terminated or not for this case
  1457. shouldRetryFunc := func(r common.OCIOperationResponse) bool {
  1458. if serviceError, ok := common.IsServiceError(r.Error); ok && serviceError.GetHTTPStatusCode() == 404 {
  1459. // resource been deleted
  1460. return false
  1461. }
  1462. if converted, ok := r.Response.(core.GetSubnetResponse); ok {
  1463. return converted.LifecycleState != core.SubnetLifecycleStateTerminated
  1464. }
  1465. return true
  1466. }
  1467. pollGetRequest := core.GetSubnetRequest{
  1468. SubnetId: id,
  1469. RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
  1470. }
  1471. _, pollErr := c.GetSubnet(ctx, pollGetRequest)
  1472. if serviceError, ok := common.IsServiceError(pollErr); !ok ||
  1473. (ok && serviceError.GetHTTPStatusCode() != 404) {
  1474. // fail if the error is not service error or
  1475. // if the error is service error and status code not equals to 404
  1476. helpers.FatalIfError(pollErr)
  1477. }
  1478. fmt.Println("subnet deleted")
  1479. }
  1480. func printf(format string, a ...interface{}) {
  1481. fmt.Printf("%s ", time.Now().Format("2006-01-02 15:04:05"))
  1482. fmt.Printf(format, a...)
  1483. }
  1484. // 根据实例OCID获取公共IP
  1485. func getInstancePublicIps(ctx context.Context, computeClient core.ComputeClient, networkClient core.VirtualNetworkClient, instanceId *string) (ips []string, err error) {
  1486. // 多次尝试,避免刚抢购到实例,实例正在预配获取不到公共IP。
  1487. for i := 0; i < 20; i++ {
  1488. vnicAttachments, attachmentsErr := ListVnicAttachments(ctx, computeClient, instanceId)
  1489. if attachmentsErr != nil {
  1490. err = errors.New("获取失败")
  1491. continue
  1492. }
  1493. if len(vnicAttachments) > 0 {
  1494. for _, vnicAttachment := range vnicAttachments {
  1495. vnic, vnicErr := GetVnic(ctx, networkClient, vnicAttachment.VnicId)
  1496. if vnicErr != nil {
  1497. printf("GetVnic error: %s\n", vnicErr.Error())
  1498. continue
  1499. }
  1500. ips = append(ips, *vnic.PublicIp)
  1501. }
  1502. return
  1503. }
  1504. time.Sleep(3 * time.Second)
  1505. }
  1506. return
  1507. }
  1508. func sendMessage(name, text string) {
  1509. if token != "" && chat_id != "" {
  1510. data := url.Values{
  1511. "parse_mode": {"Markdown"},
  1512. "chat_id": {chat_id},
  1513. "text": {"*甲骨文通知*\n名称: " + name + "\n" + "内容: " + text},
  1514. }
  1515. req, err := http.NewRequest(http.MethodPost, sendMessageUrl, strings.NewReader(data.Encode()))
  1516. if err != nil {
  1517. printf("\033[1;31mNewRequest Error: \033[0m%s\n", err.Error())
  1518. }
  1519. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  1520. client := common.BaseClient{HTTPClient: &http.Client{}}
  1521. setProxyOrNot(&client)
  1522. resp, err := client.HTTPClient.Do(req)
  1523. if err != nil {
  1524. printf("\033[1;31mTelegram 消息提醒发送失败, Error: \033[0m%s\n", err.Error())
  1525. } else {
  1526. if resp.StatusCode != 200 {
  1527. bodyBytes, err := ioutil.ReadAll(resp.Body)
  1528. var error string
  1529. if err != nil {
  1530. error = err.Error()
  1531. } else {
  1532. error = string(bodyBytes)
  1533. }
  1534. printf("\033[1;31mTelegram 消息提醒发送失败, Error: \033[0m%s\n", error)
  1535. }
  1536. }
  1537. }
  1538. }
  1539. func setProxyOrNot(client *common.BaseClient) {
  1540. if proxy != "" {
  1541. proxyURL, err := url.Parse(proxy)
  1542. if err != nil {
  1543. fmt.Println(err)
  1544. return
  1545. }
  1546. client.HTTPClient = &http.Client{
  1547. Transport: &http.Transport{
  1548. Proxy: http.ProxyURL(proxyURL),
  1549. },
  1550. }
  1551. }
  1552. }
  1553. func getInstanceState(state core.InstanceLifecycleStateEnum) string {
  1554. var chineseState string
  1555. switch state {
  1556. case core.InstanceLifecycleStateMoving:
  1557. chineseState = "正在移动"
  1558. case core.InstanceLifecycleStateProvisioning:
  1559. chineseState = "正在预配"
  1560. case core.InstanceLifecycleStateRunning:
  1561. chineseState = "正在运行"
  1562. case core.InstanceLifecycleStateStarting:
  1563. chineseState = "正在启动"
  1564. case core.InstanceLifecycleStateStopping:
  1565. chineseState = "正在停止"
  1566. case core.InstanceLifecycleStateStopped:
  1567. chineseState = "已停止 "
  1568. case core.InstanceLifecycleStateTerminating:
  1569. chineseState = "正在终止"
  1570. case core.InstanceLifecycleStateTerminated:
  1571. chineseState = "已终止 "
  1572. default:
  1573. chineseState = string(state)
  1574. }
  1575. return chineseState
  1576. }