ops_vpc_router.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 "fmt"
20 "net"
21 "time"
22
23 "github.com/sacloud/iaas-api-go"
24 "github.com/sacloud/iaas-api-go/types"
25 )
26
27 // Find is fake implementation
28 func (o *VPCRouterOp) Find(ctx context.Context, zone string, conditions *iaas.FindCondition) (*iaas.VPCRouterFindResult, error) {
29 results, _ := find(o.key, zone, conditions)
30 var values []*iaas.VPCRouter
31 for _, res := range results {
32 dest := &iaas.VPCRouter{}
33 copySameNameField(res, dest)
34 values = append(values, dest)
35 }
36 return &iaas.VPCRouterFindResult{
37 Total: len(results),
38 Count: len(results),
39 From: 0,
40 VPCRouters: values,
41 }, nil
42 }
43
44 // Create is fake implementation
45 func (o *VPCRouterOp) Create(ctx context.Context, zone string, param *iaas.VPCRouterCreateRequest) (*iaas.VPCRouter, error) {
46 result := &iaas.VPCRouter{}
47 copySameNameField(param, result)
48 fill(result, fillID, fillCreatedAt)
49
50 result.Class = "vpcrouter"
51 result.Availability = types.Availabilities.Migrating
52 result.ZoneID = zoneIDs[zone]
53 result.SettingsHash = ""
54 if result.Version == 0 {
55 result.Version = 2
56 }
57
58 ifOp := NewInterfaceOp()
59 swOp := NewSwitchOp()
60
61 ifCreateParam := &iaas.InterfaceCreateRequest{}
62 if param.Switch.Scope == types.Scopes.Shared {
63 ifCreateParam.ServerID = result.ID
64 } else {
65 _, err := swOp.Read(ctx, zone, param.Switch.ID)
66 if err != nil {
67 return nil, newErrorConflict(o.key, types.ID(0), err.Error())
68 }
69 }
70
71 iface, err := ifOp.Create(ctx, zone, ifCreateParam)
72 if err != nil {
73 return nil, newErrorConflict(o.key, types.ID(0), err.Error())
74 }
75
76 if param.Switch.Scope == types.Scopes.Shared {
77 if err := ifOp.ConnectToSharedSegment(ctx, zone, iface.ID); err != nil {
78 return nil, newErrorConflict(o.key, types.ID(0), err.Error())
79 }
80 } else {
81 if err := ifOp.ConnectToSwitch(ctx, zone, iface.ID, param.Switch.ID); err != nil {
82 return nil, newErrorConflict(o.key, types.ID(0), err.Error())
83 }
84 }
85
86 iface, err = ifOp.Read(ctx, zone, iface.ID)
87 if err != nil {
88 return nil, newErrorConflict(o.key, types.ID(0), err.Error())
89 }
90
91 vpcRouterInterface := &iaas.VPCRouterInterface{}
92 copySameNameField(iface, vpcRouterInterface)
93 if param.Switch.Scope == types.Scopes.Shared {
94 sharedIP := pool().nextSharedIP()
95 vpcRouterInterface.IPAddress = sharedIP.String()
96 vpcRouterInterface.SubnetNetworkMaskLen = sharedSegmentSwitch.NetworkMaskLen
97
98 ipv4Mask := net.CIDRMask(pool().SharedNetMaskLen, 32)
99 vpcRouterInterface.SubnetNetworkAddress = sharedIP.Mask(ipv4Mask).String()
100 vpcRouterInterface.SubnetDefaultRoute = pool().SharedDefaultGateway.String()
101 }
102 result.Interfaces = append(result.Interfaces, vpcRouterInterface)
103
104 putVPCRouter(zone, result)
105
106 id := result.ID
107 startMigration(o.key, zone, func() (interface{}, error) {
108 return o.Read(context.Background(), zone, id)
109 })
110 return result, nil
111 }
112
113 // Read is fake implementation
114 func (o *VPCRouterOp) Read(ctx context.Context, zone string, id types.ID) (*iaas.VPCRouter, error) {
115 value := getVPCRouterByID(zone, id)
116 if value == nil {
117 return nil, newErrorNotFound(o.key, id)
118 }
119 dest := &iaas.VPCRouter{}
120 copySameNameField(value, dest)
121 return dest, nil
122 }
123
124 // Update is fake implementation
125 func (o *VPCRouterOp) Update(ctx context.Context, zone string, id types.ID, param *iaas.VPCRouterUpdateRequest) (*iaas.VPCRouter, error) {
126 value, err := o.Read(ctx, zone, id)
127 if err != nil {
128 return nil, err
129 }
130 copySameNameField(param, value)
131 fill(value, fillModifiedAt)
132
133 putVPCRouter(zone, value)
134 return value, nil
135 }
136
137 // UpdateSettings is fake implementation
138 func (o *VPCRouterOp) UpdateSettings(ctx context.Context, zone string, id types.ID, param *iaas.VPCRouterUpdateSettingsRequest) (*iaas.VPCRouter, error) {
139 value, err := o.Read(ctx, zone, id)
140 if err != nil {
141 return nil, err
142 }
143 copySameNameField(param, value)
144 fill(value, fillModifiedAt)
145
146 putVPCRouter(zone, value)
147 return value, nil
148 }
149
150 // Delete is fake implementation
151 func (o *VPCRouterOp) Delete(ctx context.Context, zone string, id types.ID) error {
152 _, err := o.Read(ctx, zone, id)
153 if err != nil {
154 return err
155 }
156 ds().Delete(o.key, zone, id)
157 return nil
158 }
159
160 // Config is fake implementation
161 func (o *VPCRouterOp) Config(ctx context.Context, zone string, id types.ID) error {
162 return nil
163 }
164
165 // Boot is fake implementation
166 func (o *VPCRouterOp) Boot(ctx context.Context, zone string, id types.ID) error {
167 value, err := o.Read(ctx, zone, id)
168 if err != nil {
169 return err
170 }
171 if value.InstanceStatus.IsUp() {
172 return newErrorConflict(o.key, id, "Boot is failed")
173 }
174
175 startPowerOn(o.key, zone, func() (interface{}, error) {
176 return o.Read(context.Background(), zone, id)
177 })
178
179 return err
180 }
181
182 // Shutdown is fake implementation
183 func (o *VPCRouterOp) Shutdown(ctx context.Context, zone string, id types.ID, shutdownOption *iaas.ShutdownOption) error {
184 value, err := o.Read(ctx, zone, id)
185 if err != nil {
186 return err
187 }
188 if !value.InstanceStatus.IsUp() {
189 return newErrorConflict(o.key, id, "Shutdown is failed")
190 }
191
192 startPowerOff(o.key, zone, func() (interface{}, error) {
193 return o.Read(context.Background(), zone, id)
194 })
195
196 return err
197 }
198
199 // Reset is fake implementation
200 func (o *VPCRouterOp) Reset(ctx context.Context, zone string, id types.ID) error {
201 value, err := o.Read(ctx, zone, id)
202 if err != nil {
203 return err
204 }
205 if !value.InstanceStatus.IsUp() {
206 return newErrorConflict(o.key, id, "Reset is failed")
207 }
208
209 startPowerOn(o.key, zone, func() (interface{}, error) {
210 return o.Read(context.Background(), zone, id)
211 })
212
213 return nil
214 }
215
216 // ConnectToSwitch is fake implementation
217 func (o *VPCRouterOp) ConnectToSwitch(ctx context.Context, zone string, id types.ID, nicIndex int, switchID types.ID) error {
218 value, err := o.Read(ctx, zone, id)
219 if err != nil {
220 return err
221 }
222
223 for _, nic := range value.Interfaces {
224 if nic.Index == nicIndex {
225 return newErrorBadRequest(o.key, id, fmt.Sprintf("nic[%d] already connected to switch", nicIndex))
226 }
227 }
228
229 // find switch
230 swOp := NewSwitchOp()
231 _, err = swOp.Read(ctx, zone, switchID)
232 if err != nil {
233 return fmt.Errorf("ConnectToSwitch is failed: %s", err)
234 }
235
236 // create interface
237 ifOp := NewInterfaceOp()
238 iface, err := ifOp.Create(ctx, zone, &iaas.InterfaceCreateRequest{ServerID: id})
239 if err != nil {
240 return newErrorConflict(o.key, types.ID(0), err.Error())
241 }
242
243 if err := ifOp.ConnectToSwitch(ctx, zone, iface.ID, switchID); err != nil {
244 return newErrorConflict(o.key, types.ID(0), err.Error())
245 }
246
247 iface, err = ifOp.Read(ctx, zone, iface.ID)
248 if err != nil {
249 return newErrorConflict(o.key, types.ID(0), err.Error())
250 }
251
252 vpcRouterInterface := &iaas.VPCRouterInterface{}
253 copySameNameField(iface, vpcRouterInterface)
254 vpcRouterInterface.Index = nicIndex
255 value.Interfaces = append(value.Interfaces, vpcRouterInterface)
256
257 putVPCRouter(zone, value)
258 return nil
259 }
260
261 // DisconnectFromSwitch is fake implementation
262 func (o *VPCRouterOp) DisconnectFromSwitch(ctx context.Context, zone string, id types.ID, nicIndex int) error {
263 value, err := o.Read(ctx, zone, id)
264 if err != nil {
265 return err
266 }
267
268 var exists bool
269 var nicID types.ID
270 var interfaces []*iaas.VPCRouterInterface
271
272 for _, nic := range value.Interfaces {
273 if nic.Index == nicIndex {
274 exists = true
275 nicID = nic.ID
276 } else {
277 interfaces = append(interfaces, nic)
278 }
279 }
280 if !exists {
281 return newErrorBadRequest(o.key, id, fmt.Sprintf("nic[%d] is not exists", nicIndex))
282 }
283
284 ifOp := NewInterfaceOp()
285 if err := ifOp.DisconnectFromSwitch(ctx, zone, nicID); err != nil {
286 return newErrorConflict(o.key, types.ID(0), err.Error())
287 }
288
289 value.Interfaces = interfaces
290 putVPCRouter(zone, value)
291 return nil
292 }
293
294 // MonitorInterface is fake implementation
295 func (o *VPCRouterOp) MonitorInterface(ctx context.Context, zone string, id types.ID, index int, condition *iaas.MonitorCondition) (*iaas.InterfaceActivity, error) {
296 _, err := o.Read(ctx, zone, id)
297 if err != nil {
298 return nil, err
299 }
300
301 now := time.Now().Truncate(time.Second)
302 m := now.Minute() % 5
303 if m != 0 {
304 now.Add(time.Duration(m) * time.Minute)
305 }
306
307 res := &iaas.InterfaceActivity{}
308 for i := 0; i < 5; i++ {
309 res.Values = append(res.Values, &iaas.MonitorInterfaceValue{
310 Time: now.Add(time.Duration(i*-5) * time.Minute),
311 Send: float64(random(1000)),
312 Receive: float64(random(1000)),
313 })
314 }
315
316 return res, nil
317 }
318
319 // Status is fake implementation
320 func (o *VPCRouterOp) Status(ctx context.Context, zone string, id types.ID) (*iaas.VPCRouterStatus, error) {
321 v, err := o.Read(ctx, zone, id)
322 if err != nil {
323 return nil, err
324 }
325
326 if v.InstanceStatus.IsUp() && v.Settings.WireGuardEnabled.Bool() {
327 return &iaas.VPCRouterStatus{
328 WireGuard: &iaas.WireGuardStatus{
329 PublicKey: "fake-public-key",
330 },
331 SessionAnalysis: &iaas.VPCRouterSessionAnalysis{
332 SourceAndDestination: []*iaas.VPCRouterStatisticsValue{
333 {Name: "UDP src:127.0.0.1 dst:127.0.0.1:53", Count: 1},
334 },
335 DestinationAddress: []*iaas.VPCRouterStatisticsValue{
336 {Name: "127.0.0.1", Count: 1},
337 },
338 DestinationPort: []*iaas.VPCRouterStatisticsValue{
339 {Name: "UDP:53", Count: 1},
340 },
341 SourceAddress: []*iaas.VPCRouterStatisticsValue{
342 {Name: "127.0.0.1", Count: 1},
343 },
344 },
345 }, nil
346 }
347 return &iaas.VPCRouterStatus{}, nil
348 }
349
350 // MonitorCPU is fake implementation
351 func (o *VPCRouterOp) MonitorCPU(ctx context.Context, zone string, id types.ID, condition *iaas.MonitorCondition) (*iaas.CPUTimeActivity, error) {
352 _, err := o.Read(ctx, zone, id)
353 if err != nil {
354 return nil, err
355 }
356
357 now := time.Now().Truncate(time.Second)
358 m := now.Minute() % 5
359 if m != 0 {
360 now.Add(time.Duration(m) * time.Minute)
361 }
362
363 res := &iaas.CPUTimeActivity{}
364 for i := 0; i < 5; i++ {
365 res.Values = append(res.Values, &iaas.MonitorCPUTimeValue{
366 Time: now.Add(time.Duration(i*-5) * time.Minute),
367 CPUTime: float64(random(1000)),
368 })
369 }
370
371 return res, nil
372 }
373
374 // Logs is fake implementation
375 func (o *VPCRouterOp) Logs(ctx context.Context, zone string, id types.ID) (*iaas.VPCRouterLog, error) {
376 return &iaas.VPCRouterLog{Log: "fake"}, nil
377 }
378
379 func (o *VPCRouterOp) Ping(ctx context.Context, zone string, id types.ID, destination string) (*iaas.VPCRouterPingResults, error) {
380 return &iaas.VPCRouterPingResults{Result: []string{"fake"}}, nil
381 }
382