ops_interface.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 "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 *InterfaceOp) Find(ctx context.Context, zone string, conditions *iaas.FindCondition) (*iaas.InterfaceFindResult, error) {
28 results, _ := find(o.key, zone, conditions)
29 var values []*iaas.Interface
30 for _, res := range results {
31 dest := &iaas.Interface{}
32 copySameNameField(res, dest)
33 values = append(values, dest)
34 }
35 return &iaas.InterfaceFindResult{
36 Total: len(results),
37 Count: len(results),
38 From: 0,
39 Interfaces: values,
40 }, nil
41 }
42
43 // Create is fake implementation
44 func (o *InterfaceOp) Create(ctx context.Context, zone string, param *iaas.InterfaceCreateRequest) (*iaas.Interface, error) {
45 result := &iaas.Interface{}
46 copySameNameField(param, result)
47 fill(result, fillID, fillCreatedAt)
48
49 result.MACAddress = pool().nextMACAddress().String()
50
51 // connect to server
52 if param != nil && !param.ServerID.IsEmpty() {
53 serverOp := NewServerOp()
54 server, err := serverOp.Read(ctx, zone, param.ServerID)
55 if err == nil {
56 ifaceView := &iaas.InterfaceView{}
57 copySameNameField(result, ifaceView)
58 server.Interfaces = append(server.Interfaces, ifaceView)
59 putServer(zone, server)
60 }
61 }
62
63 putInterface(zone, result)
64 return result, nil
65 }
66
67 // Read is fake implementation
68 func (o *InterfaceOp) Read(ctx context.Context, zone string, id types.ID) (*iaas.Interface, error) {
69 value := getInterfaceByID(zone, id)
70 if value == nil {
71 return nil, newErrorNotFound(o.key, id)
72 }
73
74 dest := &iaas.Interface{}
75 copySameNameField(value, dest)
76 return dest, nil
77 }
78
79 // Update is fake implementation
80 func (o *InterfaceOp) Update(ctx context.Context, zone string, id types.ID, param *iaas.InterfaceUpdateRequest) (*iaas.Interface, error) {
81 value, err := o.Read(ctx, zone, id)
82 if err != nil {
83 return nil, err
84 }
85
86 copySameNameField(param, value)
87 fill(value, fillModifiedAt)
88
89 serverOp := NewServerOp()
90 searched, err := serverOp.Find(ctx, zone, nil)
91 if err == nil {
92 for _, server := range searched.Servers {
93 for _, iface := range server.Interfaces {
94 if iface.ID == id {
95 iface.UserIPAddress = param.UserIPAddress
96 putServer(zone, server)
97 }
98 }
99 }
100 }
101
102 putInterface(zone, value)
103 return value, nil
104 }
105
106 // Delete is fake implementation
107 func (o *InterfaceOp) Delete(ctx context.Context, zone string, id types.ID) error {
108 value, err := o.Read(ctx, zone, id)
109 if err != nil {
110 return err
111 }
112 ds().Delete(o.key, zone, id)
113
114 if !value.ServerID.IsEmpty() {
115 server, err := NewServerOp().Read(ctx, zone, value.ServerID)
116 if err == nil {
117 var deleted []*iaas.InterfaceView
118 for _, iface := range server.Interfaces {
119 if iface.ID != id {
120 deleted = append(deleted, iface)
121 }
122 }
123 server.Interfaces = deleted
124 putServer(zone, server)
125 }
126 }
127
128 return nil
129 }
130
131 // Monitor is fake implementation
132 func (o *InterfaceOp) Monitor(ctx context.Context, zone string, id types.ID, condition *iaas.MonitorCondition) (*iaas.InterfaceActivity, error) {
133 _, err := o.Read(ctx, zone, id)
134 if err != nil {
135 return nil, err
136 }
137
138 now := time.Now().Truncate(time.Second)
139 m := now.Minute() % 5
140 if m != 0 {
141 now.Add(time.Duration(m) * time.Minute)
142 }
143
144 res := &iaas.InterfaceActivity{}
145 for i := 0; i < 5; i++ {
146 res.Values = append(res.Values, &iaas.MonitorInterfaceValue{
147 Time: now.Add(time.Duration(i*-5) * time.Minute),
148 Send: float64(random(1000)),
149 Receive: float64(random(1000)),
150 })
151 }
152
153 return res, nil
154 }
155
156 // ConnectToSharedSegment is fake implementation
157 func (o *InterfaceOp) ConnectToSharedSegment(ctx context.Context, zone string, id types.ID) error {
158 value, err := o.Read(ctx, zone, id)
159 if err != nil {
160 return err
161 }
162
163 if !value.SwitchID.IsEmpty() {
164 return newErrorConflict(o.key, id,
165 fmt.Sprintf("Interface[%d] is already connected to switch[%d]", value.ID, value.SwitchID))
166 }
167
168 value.SwitchID = sharedSegmentSwitch.ID
169 putInterface(zone, value)
170
171 if !value.ServerID.IsEmpty() {
172 server, err := NewServerOp().Read(ctx, zone, value.ServerID)
173 if err == nil {
174 for _, iface := range server.Interfaces {
175 if iface.ID == id {
176 iface.SwitchScope = types.Scopes.Shared
177 iface.SwitchID = sharedSegmentSwitch.ID
178 iface.SwitchName = sharedSegmentSwitch.Name
179 }
180 }
181 putServer(zone, server)
182 }
183 }
184
185 return nil
186 }
187
188 // ConnectToSwitch is fake implementation
189 func (o *InterfaceOp) ConnectToSwitch(ctx context.Context, zone string, id types.ID, switchID types.ID) error {
190 value, err := o.Read(ctx, zone, id)
191 if err != nil {
192 return err
193 }
194 if !value.SwitchID.IsEmpty() {
195 return newErrorConflict(o.key, id,
196 fmt.Sprintf("Interface[%d] is already connected to switch[%d]", value.ID, switchID))
197 }
198
199 sw, err := NewSwitchOp().Read(ctx, zone, switchID)
200 if err != nil {
201 return err
202 }
203 sw.ServerCount++
204 putSwitch(zone, sw)
205
206 value.SwitchID = switchID
207 putInterface(zone, value)
208
209 if !value.ServerID.IsEmpty() {
210 server, err := NewServerOp().Read(ctx, zone, value.ServerID)
211 if err == nil {
212 for _, iface := range server.Interfaces {
213 if iface.ID == id {
214 iface.SwitchScope = types.Scopes.User
215 iface.SwitchID = sw.ID
216 iface.SwitchName = sw.Name
217 }
218 }
219 putServer(zone, server)
220 }
221 }
222
223 return nil
224 }
225
226 // DisconnectFromSwitch is fake implementation
227 func (o *InterfaceOp) DisconnectFromSwitch(ctx context.Context, zone string, id types.ID) error {
228 value, err := o.Read(ctx, zone, id)
229 if err != nil {
230 return err
231 }
232 if value.SwitchID.IsEmpty() {
233 return newErrorConflict(o.key, id,
234 fmt.Sprintf("Interface[%d] is already disconnected", value.ID))
235 }
236
237 value.SwitchID = types.ID(0)
238 putInterface(zone, value)
239
240 if !value.ServerID.IsEmpty() {
241 server, err := NewServerOp().Read(ctx, zone, value.ServerID)
242 if err == nil {
243 for _, iface := range server.Interfaces {
244 if iface.ID == id {
245 iface.SwitchScope = types.EScope("")
246 iface.SwitchID = types.ID(0)
247 iface.SwitchName = ""
248 }
249 }
250 putServer(zone, server)
251 }
252 }
253 return nil
254 }
255
256 // ConnectToPacketFilter is fake implementation
257 func (o *InterfaceOp) ConnectToPacketFilter(ctx context.Context, zone string, id types.ID, packetFilterID types.ID) error {
258 value, err := o.Read(ctx, zone, id)
259 if err != nil {
260 return err
261 }
262 if !value.PacketFilterID.IsEmpty() {
263 return newErrorConflict(o.key, id,
264 fmt.Sprintf("Interface[%d] is already connected to packetfilter[%s]", value.ID, value.PacketFilterID))
265 }
266
267 value.PacketFilterID = packetFilterID
268 putInterface(zone, value)
269
270 // server配下のInterfaceの修正
271 searched, err := NewServerOp().Find(ctx, zone, nil)
272 if err != nil {
273 return err
274 }
275 for _, server := range searched.Servers {
276 upd := false
277 for _, nic := range server.Interfaces {
278 if nic.ID == id {
279 nic.PacketFilterID = packetFilterID
280 upd = true
281 }
282 }
283 if upd {
284 putServer(zone, server)
285 }
286 }
287
288 return nil
289 }
290
291 // DisconnectFromPacketFilter is fake implementation
292 func (o *InterfaceOp) DisconnectFromPacketFilter(ctx context.Context, zone string, id types.ID) error {
293 value, err := o.Read(ctx, zone, id)
294 if err != nil {
295 return err
296 }
297 if value.PacketFilterID.IsEmpty() {
298 return newErrorConflict(o.key, id,
299 fmt.Sprintf("Interface[%d] is already disconnected", value.ID))
300 }
301
302 value.PacketFilterID = types.ID(0)
303 putInterface(zone, value)
304
305 // server配下のInterfaceの修正
306 searched, err := NewServerOp().Find(ctx, zone, nil)
307 if err != nil {
308 return err
309 }
310 for _, server := range searched.Servers {
311 upd := false
312 for _, nic := range server.Interfaces {
313 if nic.ID == id {
314 nic.PacketFilterID = types.ID(0)
315 upd = true
316 }
317 }
318 if upd {
319 putServer(zone, server)
320 }
321 }
322 return nil
323 }
324