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