github.com/sacloud/libsacloud/v2@v2.32.3/helper/builder/internet/builder.go (about) 1 // Copyright 2016-2022 The Libsacloud Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package internet 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 22 "github.com/sacloud/libsacloud/v2/helper/plans" 23 "github.com/sacloud/libsacloud/v2/sacloud" 24 "github.com/sacloud/libsacloud/v2/sacloud/types" 25 ) 26 27 // DefaultNotFoundRetry スイッチ+ルータ作成後のReadで404が返ってこなくなるまでに許容する404エラーの回数 28 var DefaultNotFoundRetry = 360 // デフォルトの5秒おきリトライの場合30分 29 30 // Builder スイッチ+ルータの構築を行う 31 type Builder struct { 32 Name string 33 Description string 34 Tags types.Tags 35 IconID types.ID 36 NetworkMaskLen int 37 BandWidthMbps int 38 EnableIPv6 bool 39 40 NotFoundRetry int 41 42 NoWait bool 43 44 Client *APIClient 45 } 46 47 // Validate 設定値の検証 48 func (b *Builder) Validate(ctx context.Context, zone string) error { 49 requiredValues := map[string]bool{ 50 "NetworkMaskLen": b.NetworkMaskLen == 0, 51 "BandWidthMbps": b.BandWidthMbps == 0, 52 } 53 for key, empty := range requiredValues { 54 if empty { 55 return fmt.Errorf("%s is required", key) 56 } 57 } 58 59 if b.NoWait && b.EnableIPv6 { 60 return errors.New("NoWait=true is not supported when EnableIPv6=true") 61 } 62 return nil 63 } 64 65 // Build ルータ+スイッチの作成や設定をまとめて行う 66 func (b *Builder) Build(ctx context.Context, zone string) (*sacloud.Internet, error) { 67 if b.NotFoundRetry == 0 { 68 b.NotFoundRetry = DefaultNotFoundRetry 69 } 70 71 if err := b.Validate(ctx, zone); err != nil { 72 return nil, err 73 } 74 75 internet, err := b.Client.Internet.Create(ctx, zone, &sacloud.InternetCreateRequest{ 76 Name: b.Name, 77 Description: b.Description, 78 Tags: b.Tags, 79 IconID: b.IconID, 80 NetworkMaskLen: b.NetworkMaskLen, 81 BandWidthMbps: b.BandWidthMbps, 82 }) 83 if err != nil { 84 return nil, err 85 } 86 87 if b.NoWait { 88 return internet, nil 89 } 90 91 // [HACK] ルータ作成直後は GET /internet/:id が404を返すことへの対応 92 waiter := sacloud.WaiterForApplianceUp(func() (interface{}, error) { 93 return b.Client.Internet.Read(ctx, zone, internet.ID) 94 }, b.NotFoundRetry) 95 if _, err := waiter.WaitForState(ctx); err != nil { 96 return internet, err 97 } 98 99 if b.EnableIPv6 { 100 _, err = b.Client.Internet.EnableIPv6(ctx, zone, internet.ID) 101 if err != nil { 102 return internet, err 103 } 104 } 105 106 return b.Client.Internet.Read(ctx, zone, internet.ID) 107 } 108 109 // Update スイッチ+ルータの更新 110 func (b *Builder) Update(ctx context.Context, zone string, id types.ID) (*sacloud.Internet, error) { 111 if err := b.Validate(ctx, zone); err != nil { 112 return nil, err 113 } 114 115 // check Internet is exists 116 internet, err := b.Client.Internet.Read(ctx, zone, id) 117 if err != nil { 118 return nil, err 119 } 120 121 if b.NetworkMaskLen != internet.NetworkMaskLen { 122 return nil, fmt.Errorf("unsupported operation: NetworkMaskLen is changed: current: %d new: %d", internet.NetworkMaskLen, b.NetworkMaskLen) 123 } 124 125 if internet.BandWidthMbps != b.BandWidthMbps { 126 b.Tags = plans.AppendPreviousIDTagIfAbsent(b.Tags, internet.ID) 127 // 成功するとIDが変更となる 128 internet, err = b.Client.Internet.UpdateBandWidth(ctx, zone, internet.ID, &sacloud.InternetUpdateBandWidthRequest{ 129 BandWidthMbps: b.BandWidthMbps, 130 }) 131 if err != nil { 132 return nil, err 133 } 134 } 135 136 internet, err = b.Client.Internet.Update(ctx, zone, internet.ID, &sacloud.InternetUpdateRequest{ 137 Name: b.Name, 138 Description: b.Description, 139 Tags: b.Tags, 140 IconID: b.IconID, 141 }) 142 if err != nil { 143 return nil, err 144 } 145 146 currentIPv6Enabled := len(internet.Switch.IPv6Nets) > 0 147 if b.EnableIPv6 != currentIPv6Enabled { 148 if currentIPv6Enabled { 149 if err := b.Client.Internet.DisableIPv6(ctx, zone, internet.ID, internet.Switch.IPv6Nets[0].ID); err != nil { 150 return nil, err 151 } 152 } else { 153 if _, err := b.Client.Internet.EnableIPv6(ctx, zone, internet.ID); err != nil { 154 return nil, err 155 } 156 } 157 } 158 159 return b.Client.Internet.Read(ctx, zone, internet.ID) 160 }