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