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