ops_internet.go raw
1 // Copyright 2022-2025 The sacloud/iaas-api-go 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 fake
16
17 import (
18 "context"
19 "net"
20 "time"
21
22 "github.com/sacloud/iaas-api-go"
23 "github.com/sacloud/iaas-api-go/types"
24 )
25
26 // Find is fake implementation
27 func (o *InternetOp) Find(ctx context.Context, zone string, conditions *iaas.FindCondition) (*iaas.InternetFindResult, error) {
28 results, _ := find(o.key, zone, conditions)
29 var values []*iaas.Internet
30 for _, res := range results {
31 dest := &iaas.Internet{}
32 copySameNameField(res, dest)
33 values = append(values, dest)
34 }
35 return &iaas.InternetFindResult{
36 Total: len(results),
37 Count: len(results),
38 From: 0,
39 Internet: values,
40 }, nil
41 }
42
43 // Create is fake implementation
44 func (o *InternetOp) Create(ctx context.Context, zone string, param *iaas.InternetCreateRequest) (*iaas.Internet, error) {
45 if param.NetworkMaskLen == 0 {
46 param.NetworkMaskLen = 28
47 }
48 if param.BandWidthMbps == 0 {
49 param.BandWidthMbps = 100
50 }
51
52 result := &iaas.Internet{}
53 copySameNameField(param, result)
54 fill(result, fillID, fillCreatedAt)
55
56 // assign global address
57 subnet := pool().nextSubnet(result.NetworkMaskLen)
58
59 // create switch
60 swOp := NewSwitchOp()
61 sw, err := swOp.Create(ctx, zone, &iaas.SwitchCreateRequest{
62 Name: result.Name,
63 NetworkMaskLen: subnet.networkMaskLen,
64 DefaultRoute: subnet.defaultRoute,
65 })
66 if err != nil {
67 return nil, err
68 }
69
70 sSubnet := &iaas.SwitchSubnet{
71 ID: pool().generateID(),
72 DefaultRoute: subnet.defaultRoute,
73 NetworkAddress: subnet.networkAddress,
74 NetworkMaskLen: subnet.networkMaskLen,
75 Internet: result,
76 AssignedIPAddressMax: subnet.addresses[len(subnet.addresses)-1],
77 AssignedIPAddressMin: subnet.addresses[0],
78 }
79 sw.Subnets = append(sw.Subnets, sSubnet)
80
81 // for Internet.Switch
82 switchInfo := &iaas.SwitchInfo{}
83 copySameNameField(sw, switchInfo)
84
85 iSubnet := &iaas.InternetSubnet{
86 ID: sSubnet.ID,
87 DefaultRoute: sSubnet.DefaultRoute,
88 NetworkAddress: sSubnet.NetworkAddress,
89 NetworkMaskLen: sSubnet.NetworkMaskLen,
90 }
91 switchInfo.Subnets = []*iaas.InternetSubnet{iSubnet}
92 result.Switch = switchInfo
93
94 // for raw subnet
95 rSubnet := &iaas.Subnet{}
96 copySameNameField(sSubnet, rSubnet)
97 for _, ip := range subnet.addresses {
98 rSubnet.IPAddresses = append(rSubnet.IPAddresses, &iaas.SubnetIPAddress{IPAddress: ip})
99 }
100 rSubnet.SwitchID = sw.ID
101 rSubnet.InternetID = result.ID
102
103 putSwitch(zone, sw)
104 putInternet(zone, result)
105 putSubnet(zone, rSubnet)
106 return result, nil
107 }
108
109 // Read is fake implementation
110 func (o *InternetOp) Read(ctx context.Context, zone string, id types.ID) (*iaas.Internet, error) {
111 value := getInternetByID(zone, id)
112 if value == nil {
113 return nil, newErrorNotFound(o.key, id)
114 }
115 dest := &iaas.Internet{}
116 copySameNameField(value, dest)
117 return dest, nil
118 }
119
120 // Update is fake implementation
121 func (o *InternetOp) Update(ctx context.Context, zone string, id types.ID, param *iaas.InternetUpdateRequest) (*iaas.Internet, error) {
122 value, err := o.Read(ctx, zone, id)
123 if err != nil {
124 return nil, err
125 }
126 copySameNameField(param, value)
127
128 putInternet(zone, value)
129 return value, nil
130 }
131
132 // Delete is fake implementation
133 func (o *InternetOp) Delete(ctx context.Context, zone string, id types.ID) error {
134 value, err := o.Read(ctx, zone, id)
135 if err != nil {
136 return err
137 }
138
139 // check subnets/ipv6nets
140 if len(value.Switch.Subnets) > 1 {
141 return newErrorBadRequest(ResourceInternet, value.ID, "Internet resource still have Subnets")
142 }
143 if len(value.Switch.IPv6Nets) > 1 {
144 return newErrorBadRequest(ResourceInternet, value.ID, "Internet resource still have Subnets")
145 }
146
147 swOp := NewSwitchOp()
148 if err := swOp.Delete(ctx, zone, value.Switch.ID); err != nil {
149 return err
150 }
151
152 ds().Delete(o.key, zone, id)
153 return nil
154 }
155
156 // UpdateBandWidth is fake implementation
157 func (o *InternetOp) UpdateBandWidth(ctx context.Context, zone string, id types.ID, param *iaas.InternetUpdateBandWidthRequest) (*iaas.Internet, error) {
158 value, err := o.Read(ctx, zone, id)
159 if err != nil {
160 return nil, err
161 }
162
163 value.BandWidthMbps = param.BandWidthMbps
164 putInternet(zone, value)
165 return value, nil
166 }
167
168 // AddSubnet is fake implementation
169 func (o *InternetOp) AddSubnet(ctx context.Context, zone string, id types.ID, param *iaas.InternetAddSubnetRequest) (*iaas.InternetSubnetOperationResult, error) {
170 value, err := o.Read(ctx, zone, id)
171 if err != nil {
172 return nil, err
173 }
174
175 // assign global address
176 subnet := pool().nextSubnetFull(param.NetworkMaskLen, param.NextHop)
177
178 // create switch
179 swOp := NewSwitchOp()
180 sw, err := swOp.Read(ctx, zone, value.Switch.ID)
181 if err != nil {
182 return nil, err
183 }
184
185 sSubnet := &iaas.SwitchSubnet{
186 ID: pool().generateID(),
187 NetworkAddress: subnet.networkAddress,
188 NetworkMaskLen: subnet.networkMaskLen,
189 NextHop: param.NextHop,
190 StaticRoute: param.NextHop,
191 Internet: value,
192 AssignedIPAddressMax: subnet.addresses[len(subnet.addresses)-1],
193 AssignedIPAddressMin: subnet.addresses[0],
194 }
195 sw.Subnets = append(sw.Subnets, sSubnet)
196
197 // for Internet.Switch
198 iSubnet := &iaas.InternetSubnet{
199 ID: sSubnet.ID,
200 DefaultRoute: sSubnet.DefaultRoute,
201 NetworkAddress: sSubnet.NetworkAddress,
202 NetworkMaskLen: sSubnet.NetworkMaskLen,
203 NextHop: param.NextHop,
204 StaticRoute: param.NextHop,
205 }
206 value.Switch.Subnets = append(value.Switch.Subnets, iSubnet)
207
208 // for raw subnet
209 rSubnet := &iaas.Subnet{}
210 copySameNameField(sSubnet, rSubnet)
211 for _, ip := range subnet.addresses {
212 rSubnet.IPAddresses = append(rSubnet.IPAddresses, &iaas.SubnetIPAddress{IPAddress: ip})
213 }
214 rSubnet.SwitchID = sw.ID
215 rSubnet.InternetID = value.ID
216
217 putSwitch(zone, sw)
218 putInternet(zone, value)
219 putSubnet(zone, rSubnet)
220
221 return &iaas.InternetSubnetOperationResult{
222 ID: sSubnet.ID,
223 NextHop: param.NextHop,
224 StaticRoute: param.NextHop,
225 NetworkMaskLen: sSubnet.NetworkMaskLen,
226 NetworkAddress: sSubnet.NetworkAddress,
227 IPAddresses: subnet.addresses,
228 }, nil
229 }
230
231 // UpdateSubnet is fake implementation
232 func (o *InternetOp) UpdateSubnet(ctx context.Context, zone string, id types.ID, subnetID types.ID, param *iaas.InternetUpdateSubnetRequest) (*iaas.InternetSubnetOperationResult, error) {
233 value, err := o.Read(ctx, zone, id)
234 if err != nil {
235 return nil, err
236 }
237 // create switch
238 swOp := NewSwitchOp()
239 sw, err := swOp.Read(ctx, zone, value.Switch.ID)
240 if err != nil {
241 return nil, err
242 }
243
244 rSubnet, err := NewSubnetOp().Read(ctx, zone, subnetID)
245 if err != nil {
246 return nil, err
247 }
248
249 rSubnet.NextHop = param.NextHop
250
251 var nwMaskLen int
252 var nwAddress, minAddr, maxAddr string
253 var addresses []string
254
255 for _, subnet := range sw.Subnets {
256 if subnet.ID == subnetID {
257 subnet.NextHop = param.NextHop
258 subnet.StaticRoute = param.NextHop
259
260 minAddr = subnet.AssignedIPAddressMin
261 maxAddr = subnet.AssignedIPAddressMax
262 nwMaskLen = subnet.NetworkMaskLen
263 nwAddress = subnet.NetworkAddress
264 }
265 }
266
267 for _, subnet := range value.Switch.Subnets {
268 if subnet.ID == subnetID {
269 subnet.NextHop = param.NextHop
270 subnet.StaticRoute = param.NextHop
271 }
272 }
273
274 baseIP := net.ParseIP(minAddr).To4()
275 min := baseIP[3]
276 max := net.ParseIP(maxAddr).To4()[3]
277
278 var i byte
279 for (min + i) <= max { // 境界含む
280 ip := net.IPv4(baseIP[0], baseIP[1], baseIP[2], baseIP[3]+i)
281 addresses = append(addresses, ip.String())
282 i++
283 }
284
285 putSubnet(zone, rSubnet)
286 putSwitch(zone, sw)
287 putInternet(zone, value)
288 return &iaas.InternetSubnetOperationResult{
289 ID: subnetID,
290 NextHop: param.NextHop,
291 StaticRoute: param.NextHop,
292 NetworkMaskLen: nwMaskLen,
293 NetworkAddress: nwAddress,
294 IPAddresses: addresses,
295 }, nil
296 }
297
298 // DeleteSubnet is fake implementation
299 func (o *InternetOp) DeleteSubnet(ctx context.Context, zone string, id types.ID, subnetID types.ID) error {
300 value, err := o.Read(ctx, zone, id)
301 if err != nil {
302 return err
303 }
304
305 // create switch
306 swOp := NewSwitchOp()
307 sw, err := swOp.Read(ctx, zone, value.Switch.ID)
308 if err != nil {
309 return err
310 }
311
312 var sSubnets []*iaas.SwitchSubnet
313 for _, subnet := range sw.Subnets {
314 if subnet.ID != subnetID {
315 sSubnets = append(sSubnets, subnet)
316 }
317 }
318 sw.Subnets = sSubnets
319
320 var iSubnets []*iaas.InternetSubnet
321 for _, subnet := range value.Switch.Subnets {
322 if subnet.ID != subnetID {
323 iSubnets = append(iSubnets, subnet)
324 }
325 }
326 value.Switch.Subnets = iSubnets
327
328 ds().Delete(ResourceSubnet, zone, subnetID)
329 putSwitch(zone, sw)
330 putInternet(zone, value)
331 return nil
332 }
333
334 // Monitor is fake implementation
335 func (o *InternetOp) Monitor(ctx context.Context, zone string, id types.ID, condition *iaas.MonitorCondition) (*iaas.RouterActivity, error) {
336 _, err := o.Read(ctx, zone, id)
337 if err != nil {
338 return nil, err
339 }
340
341 now := time.Now().Truncate(time.Second)
342 m := now.Minute() % 5
343 if m != 0 {
344 now.Add(time.Duration(m) * time.Minute)
345 }
346
347 res := &iaas.RouterActivity{}
348 for i := 0; i < 5; i++ {
349 res.Values = append(res.Values, &iaas.MonitorRouterValue{
350 Time: now.Add(time.Duration(i*-5) * time.Minute),
351 In: float64(random(1000)),
352 Out: float64(random(1000)),
353 })
354 }
355
356 return res, nil
357 }
358
359 // MonitorRouter is fake implementation
360 func (o *InternetOp) MonitorRouter(ctx context.Context, zone string, id types.ID, condition *iaas.MonitorCondition) (*iaas.RouterActivity, error) {
361 return o.Monitor(ctx, zone, id, condition)
362 }
363
364 // EnableIPv6 is fake implementation
365 func (o *InternetOp) EnableIPv6(ctx context.Context, zone string, id types.ID) (*iaas.IPv6NetInfo, error) {
366 value, err := o.Read(ctx, zone, id)
367 if err != nil {
368 return nil, err
369 }
370
371 ipv6net := &iaas.IPv6Net{
372 ID: pool().generateID(),
373 IPv6Prefix: "2001:db8:11aa:22bb::/64",
374 IPv6PrefixLen: 64,
375 }
376 putIPv6Net(zone, ipv6net)
377
378 ipv6netInfo := &iaas.IPv6NetInfo{}
379 copySameNameField(ipv6net, ipv6netInfo)
380
381 value.Switch.IPv6Nets = []*iaas.IPv6NetInfo{ipv6netInfo}
382 putInternet(zone, value)
383 return ipv6netInfo, nil
384 }
385
386 // DisableIPv6 is fake implementation
387 func (o *InternetOp) DisableIPv6(ctx context.Context, zone string, id types.ID, ipv6netID types.ID) error {
388 value, err := o.Read(ctx, zone, id)
389 if err != nil {
390 return err
391 }
392
393 if len(value.Switch.IPv6Nets) == 0 {
394 return nil
395 }
396
397 ds().Delete(ResourceIPv6Net, zone, value.Switch.IPv6Nets[0].ID)
398 value.Switch.IPv6Nets = []*iaas.IPv6NetInfo{}
399 putInternet(zone, value)
400 return nil
401 }
402