| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136 |
- package main
- import (
- "context"
- "errors"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "math/rand"
- "net/http"
- "net/url"
- "os"
- "strings"
- "time"
- "github.com/oracle/oci-go-sdk/v49/common"
- "github.com/oracle/oci-go-sdk/v49/core"
- "github.com/oracle/oci-go-sdk/v49/example/helpers"
- "github.com/oracle/oci-go-sdk/v49/identity"
- "gopkg.in/ini.v1"
- )
- const (
- defConfigFilePath = "./oci-help.ini"
- IPsFilePrefix = "IPs"
- )
- var (
- provider common.ConfigurationProvider
- config Config
- providerName string
- proxy string
- token string
- chat_id string
- sendMessageUrl string
- EACH bool
- )
- type Config struct {
- AvailabilityDomain string `ini:"availabilityDomain"`
- SSH_Public_Key string `ini:"ssh_authorized_key"`
- CompartmentID string `ini:"tenancy"`
- VcnDisplayName string `ini:"vcnDisplayName"`
- SubnetDisplayName string `ini:"subnetDisplayName"`
- Shape string `ini:"shape"`
- OperatingSystem string `ini:"OperatingSystem"`
- OperatingSystemVersion string `ini:"OperatingSystemVersion"`
- InstanceDisplayName string `ini:"instanceDisplayName"`
- Ocpus float32 `ini:"cpus"`
- MemoryInGBs float32 `ini:"memoryInGBs"`
- BootVolumeSizeInGBs int64 `ini:"bootVolumeSizeInGBs"`
- Sum int32 `ini:"sum"`
- Each int32 `ini:"each"`
- Retry int32 `ini:"retry"`
- CloudInit string `ini:"cloud-init"`
- MinTime int32 `ini:"minTime"`
- MaxTime int32 `ini:"maxTime"`
- }
- func main() {
- var configFilePath string
- flag.StringVar(&configFilePath, "config", defConfigFilePath, "配置文件路径")
- flag.StringVar(&configFilePath, "c", defConfigFilePath, "配置文件路径")
- flag.Parse()
- cfg, err := ini.Load(configFilePath)
- helpers.FatalIfError(err)
- sections := cfg.Sections()
- defSec := cfg.Section(ini.DefaultSection)
- proxy = defSec.Key("proxy").Value()
- token = defSec.Key("token").Value()
- chat_id = defSec.Key("chat_id").Value()
- if defSec.HasKey("EACH") {
- EACH, _ = defSec.Key("EACH").Bool()
- } else {
- EACH = true
- }
- sendMessageUrl = "https://api.telegram.org/bot" + token + "/sendMessage"
- rand.Seed(time.Now().UnixNano())
- fmt.Printf("\n\033[1;32;40m%s\033[0m\n\n", "欢迎使用甲骨文实例创建工具")
- fmt.Printf("\033[1;36;40m%s\033[0m %s\n", "1.", "开始创建实例")
- fmt.Printf("\033[1;36;40m%s\033[0m %s\n", "2.", "获取实例IP地址")
- fmt.Println("")
- fmt.Print("请选择[1-2]: ")
- var num int
- fmt.Scanln(&num)
- switch num {
- case 1:
- CreateInstances(sections, configFilePath)
- case 2:
- ListAllIPs(sections, configFilePath)
- default:
- }
- }
- func CreateInstances(sections []*ini.Section, configFile string) {
- for _, section := range sections {
- if len(section.ChildSections()) > 0 {
- provider = getProvider(configFile, section.Name(), "")
- printf("\033[1;36;40m[%s]\033[0m\n", section.Name())
- var SUM, NUM int32 = 0, 0
- sendMessage(section.Name(), "开始创建")
- // 获取可用性域
- AvailabilityDomains := ListAvailabilityDomains()
- for _, child := range section.ChildSections() {
- providerName = child.Name()
- config = Config{}
- err := child.MapTo(&config)
- helpers.FatalIfError(err)
- sum, num := LaunchInstances(AvailabilityDomains)
- SUM = SUM + sum
- NUM = NUM + num
- }
- printf("\033[1;36;40m[%s], 创建总数: %d, 创建成功 %d , 创建失败 %d\033[0m\n", section.Name(), SUM, NUM, SUM-NUM)
- text := fmt.Sprintf("结束创建。创建总数: %d, 创建成功 %d , 创建失败 %d", SUM, NUM, SUM-NUM)
- sendMessage(section.Name(), text)
- }
- }
- }
- // 返回值 sum: 创建实例总数; num: 创建成功的个数
- func LaunchInstances(ads []identity.AvailabilityDomain) (sum, num int32) {
- /* 创建实例的几种情况
- * 1. 设置了 availabilityDomain 参数,即在设置的可用性域中创建 sum 个实例。
- * 2. 没有设置 availabilityDomain 但是设置了 each 参数。即在获取的每个可用性域中创建 each 个实例,创建的实例总数 sum = each * adCount。
- * 3. 没有设置 availabilityDomain 且没有设置 each 参数,即在获取到的可用性域中创建的实例总数为 sum。
- */
- //可用性域数量
- var adCount int32 = int32(len(ads))
- adName := common.String(config.AvailabilityDomain)
- each := config.Each
- sum = config.Sum
- // 没有设置可用性域并且没有设置each时,才有用。
- var usableAds = make([]identity.AvailabilityDomain, 0)
- //可用性域不固定,即没有提供 availabilityDomain 参数
- var AD_NOT_FIXED bool = false
- var EACH_AD = false
- if adName == nil || *adName == "" {
- AD_NOT_FIXED = true
- if each > 0 {
- EACH_AD = true
- sum = each * adCount
- } else {
- EACH_AD = false
- usableAds = ads
- }
- }
- printf("\033[1;36;40m[%s] 开始创建...\033[0m\n", providerName)
- computeClient, err := core.NewComputeClientWithConfigurationProvider(provider)
- helpers.FatalIfError(err)
- setProxyOrNot(&computeClient.BaseClient)
- networkClient, err := core.NewVirtualNetworkClientWithConfigurationProvider(provider)
- helpers.FatalIfError(err)
- setProxyOrNot(&networkClient.BaseClient)
- ctx := context.Background()
- name := config.InstanceDisplayName
- if name == "" {
- name = time.Now().Format("instance-20060102-1504")
- }
- displayName := common.String(name)
- if sum > 1 {
- displayName = common.String(name + "-1")
- }
- // create the launch instance request
- request := core.LaunchInstanceRequest{}
- request.CompartmentId = common.String(config.CompartmentID)
- request.DisplayName = displayName
- // create a subnet or get the one already created
- subnet := CreateOrGetNetworkInfrastructure(ctx, networkClient)
- printf("子网: %s\n", *subnet.DisplayName)
- request.CreateVnicDetails = &core.CreateVnicDetails{SubnetId: subnet.Id}
- // Get a image.
- image, err := GetImage(ctx, computeClient)
- helpers.FatalIfError(err)
- printf("系统镜像: %s\n", *image.DisplayName)
- sd := core.InstanceSourceViaImageDetails{}
- sd.ImageId = image.Id
- if config.BootVolumeSizeInGBs > 0 {
- sd.BootVolumeSizeInGBs = common.Int64(config.BootVolumeSizeInGBs)
- }
- request.SourceDetails = sd
- request.IsPvEncryptionInTransitEnabled = common.Bool(true)
- request.Shape = common.String(config.Shape)
- if config.Ocpus > 0 && config.MemoryInGBs > 0 {
- request.ShapeConfig = &core.LaunchInstanceShapeConfigDetails{
- Ocpus: common.Float32(config.Ocpus),
- MemoryInGBs: common.Float32(config.MemoryInGBs),
- }
- }
- metaData := map[string]string{}
- metaData["ssh_authorized_keys"] = config.SSH_Public_Key
- if config.CloudInit != "" {
- metaData["user_data"] = config.CloudInit
- }
- request.Metadata = metaData
- minTime := config.MinTime
- maxTime := config.MaxTime
- SKIP_RETRY_MAP := make(map[int32]bool)
- var usableAdsTemp = make([]identity.AvailabilityDomain, 0)
- retry := config.Retry // 重试次数
- var failTimes int32 = 0 // 失败次数
- var adIndex int32 = 0 // 当前可用性域下标
- var pos int32 = 0 // for 循环次数
- var SUCCESS = false // 创建是否成功
- for pos < sum {
- if AD_NOT_FIXED {
- if EACH_AD {
- if pos%each == 0 && failTimes == 0 {
- adName = ads[adIndex].Name
- adIndex++
- }
- } else {
- if SUCCESS {
- adIndex = 0
- }
- if adIndex >= adCount {
- adIndex = 0
- }
- //adName = ads[adIndex].Name
- adName = usableAds[adIndex].Name
- adIndex++
- }
- }
- printf("\033[1;36;40m[%s] 第 %d 个实例正在创建, AD: %s\033[0m\n", providerName, pos+1, *adName)
- request.AvailabilityDomain = adName
- createResp, err := computeClient.LaunchInstance(ctx, request)
- if err == nil {
- // 创建实例成功
- SUCCESS = true
- num++ //成功个数+1
- printf("\033[1;32;40m[%s] 第 %d 个实例创建成功, 实例名称: %s\033[0m\n", providerName, pos+1, *createResp.Instance.DisplayName)
- if EACH {
- sendMessage(providerName, "创建成功,实例名称: "+*createResp.DisplayName)
- }
- ips := getInstancePublicIps(ctx, computeClient, networkClient, createResp.Instance.Id)
- strIps := strings.Join(ips, ",")
- printf("\033[1;32;40m[%s] 实例名称: %s, IP: %s\033[0m\n", providerName, *createResp.Instance.DisplayName, strIps)
- if EACH {
- sendMessage(providerName, "实例名称: "+*createResp.DisplayName+", IP: "+strIps)
- }
- sleepRandomSecond(minTime, maxTime)
- displayName = common.String(fmt.Sprintf("%s-%d", name, pos+1))
- request.DisplayName = displayName
- } else {
- // 创建实例失败
- SUCCESS = false
- // 错误信息
- errInfo := err.Error()
- // 是否跳过重试
- SKIP_RETRY := false
- //isRetryable := common.IsErrorRetryableByDefault(err)
- //fmt.Println("IsErrorRetryableByDefault", isRetryable)
- isNetErr := common.IsNetworkError(err)
- servErr, isServErr := common.IsServiceError(err)
- if isNetErr || (isServErr && (servErr.GetHTTPStatusCode() == 409 || servErr.GetHTTPStatusCode() == 429 || (500 <= servErr.GetHTTPStatusCode() && servErr.GetHTTPStatusCode() < 505))) {
- // 可重试
- if isServErr {
- errInfo = servErr.GetMessage()
- }
- printf("\033[1;31;40m[%s] 第 %d 个实例创建失败, Error: \033[0m%s\n", providerName, pos+1, errInfo)
- SKIP_RETRY = false
- if AD_NOT_FIXED && !EACH_AD {
- SKIP_RETRY_MAP[adIndex-1] = false
- }
- } else {
- // 无需重试
- if isServErr {
- errInfo = servErr.GetMessage()
- }
- printf("\033[1;31;40m[%s] 第 %d 个实例创建失败, Error: \033[0m%s\n", providerName, pos+1, errInfo)
- if EACH {
- sendMessage(providerName, "创建失败,Error: "+errInfo)
- }
- SKIP_RETRY = true
- if AD_NOT_FIXED && !EACH_AD {
- SKIP_RETRY_MAP[adIndex-1] = true
- }
- }
- sleepRandomSecond(minTime, maxTime)
- if AD_NOT_FIXED {
- if !EACH_AD {
- if adIndex < adCount {
- // 没有设置可用性域,且没有设置each。即在获取到的每个可用性域里尝试创建。当前使用的可用性域不是最后一个,继续尝试。
- continue
- } else {
- // 当前使用的可用性域是最后一个,判断失败次数是否达到重试次数,未达到重试次数继续尝试。
- failTimes++
- for index, skip := range SKIP_RETRY_MAP {
- if !skip {
- usableAdsTemp = append(usableAdsTemp, usableAds[index])
- }
- }
- // 重新设置 usableAds
- usableAds = usableAdsTemp
- adCount = int32(len(usableAds))
- // 重置变量
- usableAdsTemp = nil
- for k := range SKIP_RETRY_MAP {
- delete(SKIP_RETRY_MAP, k)
- }
- // 判断是否需要重试
- if (retry < 0 || failTimes <= retry) && adCount > 0 {
- continue
- }
- }
- } else {
- // 没有设置可用性域,且设置了each,即在每个域创建each个实例。判断失败次数继续尝试。
- failTimes++
- if (retry < 0 || failTimes <= retry) && !SKIP_RETRY {
- continue
- }
- }
- } else {
- //设置了可用性域,判断是否需要重试
- failTimes++
- if (retry < 0 || failTimes <= retry) && !SKIP_RETRY {
- continue
- }
- }
- }
- // 重置变量
- usableAds = ads
- adCount = int32(len(usableAds))
- usableAdsTemp = nil
- for k := range SKIP_RETRY_MAP {
- delete(SKIP_RETRY_MAP, k)
- }
- // 成功或者失败次数达到重试次数,重置失败次数为0
- failTimes = 0
- // for 循环次数+1
- pos++
- }
- return
- }
- func sleepRandomSecond(min, max int32) {
- var second int32
- if min <= 0 || max <= 0 {
- second = 1
- } else if min >= max {
- second = max
- } else {
- second = rand.Int31n(max-min) + min
- }
- printf("Sleep %d Second...\n", second)
- time.Sleep(time.Duration(second) * time.Second)
- }
- func ListAllIPs(sections []*ini.Section, configFile string) {
- IPsFilePath := IPsFilePrefix + "-" + time.Now().Format("2006-01-02-150405.txt")
- _, err := os.Stat(IPsFilePath)
- if err != nil && os.IsNotExist(err) {
- os.Create(IPsFilePath)
- }
- printf("获取实例IP地址...\n")
- for _, section := range sections {
- if len(section.ChildSections()) > 0 {
- provider = getProvider(configFile, section.Name(), "")
- ListInstancesIPs(IPsFilePath, section.Name())
- }
- }
- printf("获取实例IP地址完成,请查看文件 %s\n", IPsFilePath)
- }
- func ListInstancesIPs(filePath string, sectionName string) {
- ctx := context.Background()
- computeClient, err := core.NewComputeClientWithConfigurationProvider(provider)
- helpers.FatalIfError(err)
- setProxyOrNot(&computeClient.BaseClient)
- netClient, err := core.NewVirtualNetworkClientWithConfigurationProvider(provider)
- helpers.FatalIfError(err)
- setProxyOrNot(&netClient.BaseClient)
- vnicAttachments, err := ListVnicAttachments(ctx, computeClient, nil)
- if err != nil {
- printf("ListVnicAttachments Error: %s\n", err.Error())
- }
- file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
- if err != nil {
- printf("打开文件失败, Error: %s\n", err.Error())
- return
- }
- _, err = io.WriteString(file, "["+sectionName+"]\n")
- if err != nil {
- printf("%s\n", err.Error())
- }
- for _, vnicAttachment := range vnicAttachments {
- vnic, err := GetVnic(ctx, netClient, vnicAttachment.VnicId)
- if err != nil {
- printf("IP地址获取失败, %s\n", err.Error())
- continue
- }
- printf("实例: %s, IP: %s\n", *vnic.DisplayName, *vnic.PublicIp)
- _, err = io.WriteString(file, "实例: "+*vnic.DisplayName+", IP: "+*vnic.PublicIp+"\n")
- if err != nil {
- printf("写入文件失败, Error: %s\n", err.Error())
- }
- }
- _, err = io.WriteString(file, "\n")
- if err != nil {
- printf("%s\n", err.Error())
- }
- }
- // ExampleLaunchInstance does create an instance
- // NOTE: launch instance will create a new instance and VCN. please make sure delete the instance
- // after execute this sample code, otherwise, you will be charged for the running instance
- func ExampleLaunchInstance() {
- c, err := core.NewComputeClientWithConfigurationProvider(provider)
- helpers.FatalIfError(err)
- networkClient, err := core.NewVirtualNetworkClientWithConfigurationProvider(provider)
- helpers.FatalIfError(err)
- ctx := context.Background()
- // create the launch instance request
- request := core.LaunchInstanceRequest{}
- request.CompartmentId = common.String(config.CompartmentID)
- request.DisplayName = common.String(config.InstanceDisplayName)
- request.AvailabilityDomain = common.String(config.AvailabilityDomain)
- // create a subnet or get the one already created
- subnet := CreateOrGetNetworkInfrastructure(ctx, networkClient)
- fmt.Println("subnet created")
- request.CreateVnicDetails = &core.CreateVnicDetails{SubnetId: subnet.Id}
- // get a image
- image := listImages(ctx, c)[0]
- fmt.Println("list images")
- request.SourceDetails = core.InstanceSourceViaImageDetails{
- ImageId: image.Id,
- BootVolumeSizeInGBs: common.Int64(config.BootVolumeSizeInGBs),
- }
- // use [config.Shape] to create instance
- request.Shape = common.String(config.Shape)
- request.ShapeConfig = &core.LaunchInstanceShapeConfigDetails{
- Ocpus: common.Float32(config.Ocpus),
- MemoryInGBs: common.Float32(config.MemoryInGBs),
- }
- // add ssh_authorized_keys
- //metaData := map[string]string{
- // "ssh_authorized_keys": config.SSH_Public_Key,
- //}
- //request.Metadata = metaData
- request.Metadata = map[string]string{"ssh_authorized_keys": config.SSH_Public_Key}
- // default retry policy will retry on non-200 response
- request.RequestMetadata = helpers.GetRequestMetadataWithDefaultRetryPolicy()
- createResp, err := c.LaunchInstance(ctx, request)
- helpers.FatalIfError(err)
- fmt.Println("launching instance")
- // should retry condition check which returns a bool value indicating whether to do retry or not
- // it checks the lifecycle status equals to Running or not for this case
- shouldRetryFunc := func(r common.OCIOperationResponse) bool {
- if converted, ok := r.Response.(core.GetInstanceResponse); ok {
- return converted.LifecycleState != core.InstanceLifecycleStateRunning
- }
- return true
- }
- // create get instance request with a retry policy which takes a function
- // to determine shouldRetry or not
- pollingGetRequest := core.GetInstanceRequest{
- InstanceId: createResp.Instance.Id,
- RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
- }
- instance, pollError := c.GetInstance(ctx, pollingGetRequest)
- helpers.FatalIfError(pollError)
- fmt.Println("instance launched")
- // 创建辅助 VNIC 并将其附加到指定的实例
- attachVnicResponse, err := c.AttachVnic(context.Background(), core.AttachVnicRequest{
- AttachVnicDetails: core.AttachVnicDetails{
- CreateVnicDetails: &core.CreateVnicDetails{
- SubnetId: subnet.Id,
- AssignPublicIp: common.Bool(true),
- },
- InstanceId: instance.Id,
- },
- })
- helpers.FatalIfError(err)
- fmt.Println("vnic attached")
- vnicState := attachVnicResponse.VnicAttachment.LifecycleState
- for vnicState != core.VnicAttachmentLifecycleStateAttached {
- time.Sleep(15 * time.Second)
- getVnicAttachmentRequest, err := c.GetVnicAttachment(context.Background(), core.GetVnicAttachmentRequest{
- VnicAttachmentId: attachVnicResponse.Id,
- })
- helpers.FatalIfError(err)
- vnicState = getVnicAttachmentRequest.VnicAttachment.LifecycleState
- }
- // 分离并删除指定的辅助 VNIC
- _, err = c.DetachVnic(context.Background(), core.DetachVnicRequest{
- VnicAttachmentId: attachVnicResponse.Id,
- })
- helpers.FatalIfError(err)
- fmt.Println("vnic dettached")
- defer func() {
- terminateInstance(ctx, c, createResp.Id)
- client, clerr := core.NewVirtualNetworkClientWithConfigurationProvider(common.DefaultConfigProvider())
- helpers.FatalIfError(clerr)
- vcnID := subnet.VcnId
- deleteSubnet(ctx, client, subnet.Id)
- deleteVcn(ctx, client, vcnID)
- }()
- // Output:
- // subnet created
- // list images
- // list shapes
- // launching instance
- // instance launched
- // vnic attached
- // vnic dettached
- // terminating instance
- // instance terminated
- // deleteing subnet
- // subnet deleted
- // deleteing VCN
- // VCN deleted
- }
- func getProvider(configPath, profile, privateKeyPassword string) common.ConfigurationProvider {
- //provider := common.DefaultConfigProvider()
- //provider, err := common.ConfigurationProviderFromFile("./oci-config", "")
- provider, err := common.ConfigurationProviderFromFileWithProfile(configPath, profile, privateKeyPassword)
- helpers.FatalIfError(err)
- return provider
- }
- // 创建或获取基础网络设施
- func CreateOrGetNetworkInfrastructure(ctx context.Context, c core.VirtualNetworkClient) core.Subnet {
- vcn := createOrGetVcn(ctx, c)
- gateway := createOrGetInternetGateway(c, vcn.Id)
- createOrGetRouteTable(c, gateway.Id, vcn.Id)
- subnet := createOrGetSubnetWithDetails(
- ctx, c, vcn.Id,
- common.String(config.SubnetDisplayName),
- common.String("10.0.0.0/24"),
- common.String("subnetdns"),
- common.String(config.AvailabilityDomain))
- return subnet
- }
- // CreateOrGetSubnetWithDetails either creates a new Virtual Cloud Network (VCN) or get the one already exist
- // with detail info
- func createOrGetSubnetWithDetails(ctx context.Context, c core.VirtualNetworkClient, vcnID *string,
- displayName *string, cidrBlock *string, dnsLabel *string, availableDomain *string) core.Subnet {
- subnets := listSubnets(ctx, c, vcnID)
- if displayName == nil {
- displayName = common.String(config.SubnetDisplayName)
- }
- if len(subnets) > 0 && *displayName == "" {
- return subnets[0]
- }
- // check if the subnet has already been created
- for _, element := range subnets {
- if *element.DisplayName == *displayName {
- // find the subnet, return it
- return element
- }
- }
- // create a new subnet
- printf("开始创建Subnet(没有可用的Subnet,或指定的Subnet不存在)\n")
- // 子网名称为空,以当前时间为名称创建子网
- if *displayName == "" {
- displayName = common.String(time.Now().Format("subnet-20060102-1504"))
- }
- request := core.CreateSubnetRequest{}
- //request.AvailabilityDomain = availableDomain //省略此属性创建区域性子网(regional subnet),提供此属性创建特定于可用性域的子网。建议创建区域性子网。
- request.CompartmentId = &config.CompartmentID
- request.CidrBlock = cidrBlock
- request.DisplayName = displayName
- request.DnsLabel = dnsLabel
- request.RequestMetadata = helpers.GetRequestMetadataWithDefaultRetryPolicy()
- request.VcnId = vcnID
- r, err := c.CreateSubnet(ctx, request)
- helpers.FatalIfError(err)
- // retry condition check, stop unitl return true
- pollUntilAvailable := func(r common.OCIOperationResponse) bool {
- if converted, ok := r.Response.(core.GetSubnetResponse); ok {
- return converted.LifecycleState != core.SubnetLifecycleStateAvailable
- }
- return true
- }
- pollGetRequest := core.GetSubnetRequest{
- SubnetId: r.Id,
- RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(pollUntilAvailable),
- }
- // wait for lifecyle become running
- _, pollErr := c.GetSubnet(ctx, pollGetRequest)
- helpers.FatalIfError(pollErr)
- // update the security rules
- getReq := core.GetSecurityListRequest{
- SecurityListId: common.String(r.SecurityListIds[0]),
- }
- getResp, err := c.GetSecurityList(ctx, getReq)
- helpers.FatalIfError(err)
- // this security rule allows remote control the instance
- /*portRange := core.PortRange{
- Max: common.Int(1521),
- Min: common.Int(1521),
- }*/
- newRules := append(getResp.IngressSecurityRules, core.IngressSecurityRule{
- //Protocol: common.String("6"), // TCP
- Protocol: common.String("all"), // 允许所有协议
- Source: common.String("0.0.0.0/0"),
- /*TcpOptions: &core.TcpOptions{
- DestinationPortRange: &portRange, // 省略该参数,允许所有目标端口。
- },*/
- })
- updateReq := core.UpdateSecurityListRequest{
- SecurityListId: common.String(r.SecurityListIds[0]),
- }
- updateReq.IngressSecurityRules = newRules
- _, err = c.UpdateSecurityList(ctx, updateReq)
- helpers.FatalIfError(err)
- printf("Subnet创建成功: %s\n", *r.Subnet.DisplayName)
- return r.Subnet
- }
- // 列出指定虚拟云网络 (VCN) 中的所有子网,如果该 VCN 不存在会创建 VCN
- func listSubnets(ctx context.Context, c core.VirtualNetworkClient, vcnID *string) []core.Subnet {
- request := core.ListSubnetsRequest{
- CompartmentId: &config.CompartmentID,
- VcnId: vcnID,
- }
- r, err := c.ListSubnets(ctx, request)
- helpers.FatalIfError(err)
- return r.Items
- }
- // 创建一个新的虚拟云网络 (VCN) 或获取已经存在的虚拟云网络
- func createOrGetVcn(ctx context.Context, c core.VirtualNetworkClient) core.Vcn {
- vcnItems := listVcns(ctx, c)
- displayName := common.String(config.VcnDisplayName)
- if len(vcnItems) > 0 && *displayName == "" {
- return vcnItems[0]
- }
- for _, element := range vcnItems {
- if *element.DisplayName == config.VcnDisplayName {
- // VCN already created, return it
- return element
- }
- }
- // create a new VCN
- printf("开始创建VCN(没有可用的VCN,或指定的VCN不存在)\n")
- if *displayName == "" {
- displayName = common.String(time.Now().Format("vcn-20060102-1504"))
- }
- request := core.CreateVcnRequest{}
- request.CidrBlock = common.String("10.0.0.0/16")
- request.CompartmentId = common.String(config.CompartmentID)
- request.DisplayName = displayName
- request.DnsLabel = common.String("vcndns")
- r, err := c.CreateVcn(ctx, request)
- helpers.FatalIfError(err)
- printf("VCN创建成功: %s\n", *r.Vcn.DisplayName)
- return r.Vcn
- }
- // 列出所有虚拟云网络 (VCN)
- func listVcns(ctx context.Context, c core.VirtualNetworkClient) []core.Vcn {
- request := core.ListVcnsRequest{
- CompartmentId: &config.CompartmentID,
- }
- r, err := c.ListVcns(ctx, request)
- helpers.FatalIfError(err)
- return r.Items
- }
- // 创建或者获取 Internet 网关
- func createOrGetInternetGateway(c core.VirtualNetworkClient, vcnID *string) (gateway core.InternetGateway) {
- ctx := context.Background()
- //List Gateways
- listGWRequest := core.ListInternetGatewaysRequest{
- CompartmentId: &config.CompartmentID,
- VcnId: vcnID,
- }
- listGWRespone, err := c.ListInternetGateways(ctx, listGWRequest)
- if err != nil {
- printf("Internet gateway list error: %s\n", err.Error())
- }
- if len(listGWRespone.Items) >= 1 {
- //Gateway with name already exists
- gateway = listGWRespone.Items[0]
- } else {
- //Create new Gateway
- printf("开始创建Internet网关\n")
- enabled := true
- createGWDetails := core.CreateInternetGatewayDetails{
- CompartmentId: &config.CompartmentID,
- IsEnabled: &enabled,
- VcnId: vcnID,
- }
- createGWRequest := core.CreateInternetGatewayRequest{CreateInternetGatewayDetails: createGWDetails}
- createGWResponse, err := c.CreateInternetGateway(ctx, createGWRequest)
- if err != nil {
- printf("Internet gateway create error: %s\n", err.Error())
- }
- gateway = createGWResponse.InternetGateway
- printf("Internet网关创建成功: %s\n", *gateway.DisplayName)
- }
- return
- }
- // 创建或者获取路由表
- func createOrGetRouteTable(c core.VirtualNetworkClient, gatewayID, VcnID *string) (routeTable core.RouteTable) {
- ctx := context.Background()
- //List Route Table
- listRTRequest := core.ListRouteTablesRequest{
- CompartmentId: &config.CompartmentID,
- VcnId: VcnID,
- }
- listRTResponse, err := c.ListRouteTables(ctx, listRTRequest)
- if err != nil {
- printf("Route table list error: %s\n", err.Error())
- }
- cidrRange := "0.0.0.0/0"
- rr := core.RouteRule{
- NetworkEntityId: gatewayID,
- Destination: &cidrRange,
- DestinationType: core.RouteRuleDestinationTypeCidrBlock,
- }
- if len(listRTResponse.Items) >= 1 {
- //Default Route Table found and has at least 1 route rule
- if len(listRTResponse.Items[0].RouteRules) >= 1 {
- routeTable = listRTResponse.Items[0]
- //Default Route table needs route rule adding
- } else {
- printf("路由表未添加规则,开始添加Internet路由规则\n")
- updateRTDetails := core.UpdateRouteTableDetails{
- RouteRules: []core.RouteRule{rr},
- }
- updateRTRequest := core.UpdateRouteTableRequest{
- RtId: listRTResponse.Items[0].Id,
- UpdateRouteTableDetails: updateRTDetails,
- }
- updateRTResponse, err := c.UpdateRouteTable(ctx, updateRTRequest)
- if err != nil {
- printf("Error updating route table: %s\n", err)
- }
- printf("Internet路由规则添加成功\n")
- routeTable = updateRTResponse.RouteTable
- }
- } else {
- //No default route table found
- printf("Error could not find VCN default route table, VCN OCID: %s Could not find route table.\n", *VcnID)
- }
- return
- }
- // 获取符合条件系统镜像中的第一个
- func GetImage(ctx context.Context, c core.ComputeClient) (image core.Image, err error) {
- images := listImages(ctx, c)
- if len(images) > 0 {
- image = images[0]
- } else {
- err = fmt.Errorf("未找到[%s %s]的镜像, 或该镜像不支持[%s]", config.OperatingSystem, config.OperatingSystemVersion, config.Shape)
- }
- return
- }
- // 列出所有符合条件的系统镜像
- func listImages(ctx context.Context, c core.ComputeClient) []core.Image {
- request := core.ListImagesRequest{
- CompartmentId: common.String(config.CompartmentID),
- OperatingSystem: common.String(config.OperatingSystem),
- OperatingSystemVersion: common.String(config.OperatingSystemVersion),
- Shape: common.String(config.Shape),
- }
- r, err := c.ListImages(ctx, request)
- helpers.FatalIfError(err)
- return r.Items
- }
- // ListShapes Lists the shapes that can be used to launch an instance within the specified compartment.
- func listShapes(ctx context.Context, c core.ComputeClient, imageID *string) []core.Shape {
- request := core.ListShapesRequest{
- CompartmentId: common.String(config.CompartmentID),
- ImageId: imageID,
- }
- r, err := c.ListShapes(ctx, request)
- helpers.FatalIfError(err)
- if r.Items == nil || len(r.Items) == 0 {
- log.Fatalln("Invalid response from ListShapes")
- }
- return r.Items
- }
- // 列出符合条件的可用性域
- func ListAvailabilityDomains() []identity.AvailabilityDomain {
- c, err := identity.NewIdentityClientWithConfigurationProvider(provider)
- helpers.FatalIfError(err)
- setProxyOrNot(&c.BaseClient)
- req := identity.ListAvailabilityDomainsRequest{}
- compartmentID, err := provider.TenancyOCID()
- helpers.FatalIfError(err)
- req.CompartmentId = common.String(compartmentID)
- resp, err := c.ListAvailabilityDomains(context.Background(), req)
- helpers.FatalIfError(err)
- return resp.Items
- }
- func ListInstances(ctx context.Context, c core.ComputeClient) []core.Instance {
- compartmentID, err := provider.TenancyOCID()
- helpers.FatalIfError(err)
- req := core.ListInstancesRequest{
- CompartmentId: &compartmentID,
- }
- resp, err := c.ListInstances(ctx, req)
- helpers.FatalIfError(err)
- return resp.Items
- }
- func ListVnicAttachments(ctx context.Context, c core.ComputeClient, instanceId *string) ([]core.VnicAttachment, error) {
- compartmentID, err := provider.TenancyOCID()
- helpers.FatalIfError(err)
- req := core.ListVnicAttachmentsRequest{CompartmentId: &compartmentID}
- if instanceId != nil && *instanceId != "" {
- req.InstanceId = instanceId
- }
- resp, err := c.ListVnicAttachments(ctx, req)
- return resp.Items, err
- }
- func GetVnic(ctx context.Context, c core.VirtualNetworkClient, vnicID *string) (core.Vnic, error) {
- req := core.GetVnicRequest{VnicId: vnicID}
- resp, err := c.GetVnic(ctx, req)
- if err != nil && resp.RawResponse != nil {
- err = errors.New(resp.RawResponse.Status)
- }
- return resp.Vnic, err
- }
- func listPublicIPs(ctx context.Context, c core.VirtualNetworkClient, ad *string) []core.PublicIp {
- com, err := provider.TenancyOCID()
- helpers.FatalIfError(err)
- req := core.ListPublicIpsRequest{
- Scope: core.ListPublicIpsScopeAvailabilityDomain,
- CompartmentId: &com,
- AvailabilityDomain: ad,
- }
- resp, err := c.ListPublicIps(ctx, req)
- helpers.FatalIfError(err)
- return resp.Items
- }
- // 终止实例
- func terminateInstance(ctx context.Context, c core.ComputeClient, id *string) {
- request := core.TerminateInstanceRequest{
- InstanceId: id,
- RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
- }
- _, err := c.TerminateInstance(ctx, request)
- helpers.FatalIfError(err)
- fmt.Println("terminating instance")
- // should retry condition check which returns a bool value indicating whether to do retry or not
- // it checks the lifecycle status equals to Terminated or not for this case
- shouldRetryFunc := func(r common.OCIOperationResponse) bool {
- if converted, ok := r.Response.(core.GetInstanceResponse); ok {
- return converted.LifecycleState != core.InstanceLifecycleStateTerminated
- }
- return true
- }
- pollGetRequest := core.GetInstanceRequest{
- InstanceId: id,
- RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
- }
- _, pollErr := c.GetInstance(ctx, pollGetRequest)
- helpers.FatalIfError(pollErr)
- fmt.Println("instance terminated")
- }
- // 删除虚拟云网络
- func deleteVcn(ctx context.Context, c core.VirtualNetworkClient, id *string) {
- request := core.DeleteVcnRequest{
- VcnId: id,
- RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
- }
- fmt.Println("deleteing VCN")
- _, err := c.DeleteVcn(ctx, request)
- helpers.FatalIfError(err)
- // should retry condition check which returns a bool value indicating whether to do retry or not
- // it checks the lifecycle status equals to Terminated or not for this case
- shouldRetryFunc := func(r common.OCIOperationResponse) bool {
- if serviceError, ok := common.IsServiceError(r.Error); ok && serviceError.GetHTTPStatusCode() == 404 {
- // resource been deleted, stop retry
- return false
- }
- if converted, ok := r.Response.(core.GetVcnResponse); ok {
- return converted.LifecycleState != core.VcnLifecycleStateTerminated
- }
- return true
- }
- pollGetRequest := core.GetVcnRequest{
- VcnId: id,
- RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
- }
- _, pollErr := c.GetVcn(ctx, pollGetRequest)
- if serviceError, ok := common.IsServiceError(pollErr); !ok ||
- (ok && serviceError.GetHTTPStatusCode() != 404) {
- // fail if the error is not service error or
- // if the error is service error and status code not equals to 404
- helpers.FatalIfError(pollErr)
- }
- fmt.Println("VCN deleted")
- }
- // 删除子网
- func deleteSubnet(ctx context.Context, c core.VirtualNetworkClient, id *string) {
- request := core.DeleteSubnetRequest{
- SubnetId: id,
- RequestMetadata: helpers.GetRequestMetadataWithDefaultRetryPolicy(),
- }
- _, err := c.DeleteSubnet(context.Background(), request)
- helpers.FatalIfError(err)
- fmt.Println("deleteing subnet")
- // should retry condition check which returns a bool value indicating whether to do retry or not
- // it checks the lifecycle status equals to Terminated or not for this case
- shouldRetryFunc := func(r common.OCIOperationResponse) bool {
- if serviceError, ok := common.IsServiceError(r.Error); ok && serviceError.GetHTTPStatusCode() == 404 {
- // resource been deleted
- return false
- }
- if converted, ok := r.Response.(core.GetSubnetResponse); ok {
- return converted.LifecycleState != core.SubnetLifecycleStateTerminated
- }
- return true
- }
- pollGetRequest := core.GetSubnetRequest{
- SubnetId: id,
- RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(shouldRetryFunc),
- }
- _, pollErr := c.GetSubnet(ctx, pollGetRequest)
- if serviceError, ok := common.IsServiceError(pollErr); !ok ||
- (ok && serviceError.GetHTTPStatusCode() != 404) {
- // fail if the error is not service error or
- // if the error is service error and status code not equals to 404
- helpers.FatalIfError(pollErr)
- }
- fmt.Println("subnet deleted")
- }
- func printf(format string, a ...interface{}) {
- fmt.Printf("%s ", time.Now().Format("2006-01-02 15:04:05"))
- fmt.Printf(format, a...)
- }
- // 根据实例OCID获取公共IP
- func getInstancePublicIps(ctx context.Context, computeClient core.ComputeClient, networkClient core.VirtualNetworkClient, instanceId *string) (ips []string) {
- var err error
- var vnicAttachments []core.VnicAttachment
- var vnic core.Vnic
- vnicAttachments, err = ListVnicAttachments(ctx, computeClient, instanceId)
- if err != nil {
- printf("ListVnicAttachments error: %s\n", err.Error())
- return
- }
- for _, vnicAttachment := range vnicAttachments {
- vnic, err = GetVnic(ctx, networkClient, vnicAttachment.VnicId)
- if err != nil {
- printf("GetVnic error: %s\n", err.Error())
- continue
- }
- ips = append(ips, *vnic.PublicIp)
- }
- return
- }
- func sendMessage(name, text string) {
- if token != "" && chat_id != "" {
- data := url.Values{
- "parse_mode": {"Markdown"},
- "chat_id": {chat_id},
- "text": {"*甲骨文通知*\n名称: " + name + "\n" + "内容: " + text},
- }
- req, err := http.NewRequest(http.MethodPost, sendMessageUrl, strings.NewReader(data.Encode()))
- if err != nil {
- printf("\033[1;31;40mNewRequest Error: \033[0m%s\n", err.Error())
- }
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- client := common.BaseClient{HTTPClient: &http.Client{}}
- setProxyOrNot(&client)
- resp, err := client.HTTPClient.Do(req)
- if err != nil {
- printf("\033[1;31;40mTelegram 消息提醒发送失败, Error: \033[0m%s\n", err.Error())
- } else {
- if resp.StatusCode != 200 {
- bodyBytes, err := ioutil.ReadAll(resp.Body)
- var error string
- if err != nil {
- error = err.Error()
- } else {
- error = string(bodyBytes)
- }
- printf("\033[1;31;40mTelegram 消息提醒发送失败, Error: \033[0m%s\n", error)
- }
- }
- }
- }
- func setProxyOrNot(client *common.BaseClient) {
- if proxy != "" {
- proxyURL, err := url.Parse(proxy)
- helpers.FatalIfError(err)
- client.HTTPClient = &http.Client{
- Transport: &http.Transport{
- Proxy: http.ProxyURL(proxyURL),
- },
- }
- }
- }
|