github.com/sacloud/iaas-api-go@v1.12.0/fake/ops_disk.go (about)

     1  // Copyright 2022-2023 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 *DiskOp) Find(ctx context.Context, zone string, conditions *iaas.FindCondition) (*iaas.DiskFindResult, error) {
    28  	results, _ := find(o.key, zone, conditions)
    29  	var values []*iaas.Disk
    30  	for _, res := range results {
    31  		dest := &iaas.Disk{}
    32  		copySameNameField(res, dest)
    33  		values = append(values, dest)
    34  	}
    35  	return &iaas.DiskFindResult{
    36  		Total: len(results),
    37  		Count: len(results),
    38  		From:  0,
    39  		Disks: values,
    40  	}, nil
    41  }
    42  
    43  // Create is fake implementation
    44  func (o *DiskOp) Create(ctx context.Context, zone string, param *iaas.DiskCreateRequest, distantFrom []types.ID) (*iaas.Disk, error) {
    45  	result := &iaas.Disk{}
    46  	copySameNameField(param, result)
    47  	fill(result, fillID, fillCreatedAt, fillDiskPlan)
    48  	result.Availability = types.Availabilities.Migrating
    49  
    50  	result.Storage = &iaas.Storage{
    51  		ID:   types.ID(123456789012),
    52  		Name: "dummy",
    53  	}
    54  
    55  	if result.Connection == types.EDiskConnection("") {
    56  		result.Connection = types.DiskConnections.VirtIO
    57  	}
    58  	if !param.SourceArchiveID.IsEmpty() {
    59  		archiveOp := NewArchiveOp()
    60  		source, err := archiveOp.Read(ctx, zone, param.SourceArchiveID)
    61  		if err != nil {
    62  			return nil, newErrorBadRequest(o.key, types.ID(0), "SourceArchive is not found")
    63  		}
    64  		result.SourceArchiveAvailability = source.Availability
    65  	}
    66  	if !param.SourceDiskID.IsEmpty() {
    67  		source, err := o.Read(ctx, zone, param.SourceDiskID)
    68  		if err != nil {
    69  			return nil, newErrorBadRequest(o.key, types.ID(0), "SourceDisk is not found")
    70  		}
    71  		result.SourceDiskAvailability = source.Availability
    72  	}
    73  	if !param.ServerID.IsEmpty() {
    74  		server, err := NewServerOp().Read(ctx, zone, param.ServerID)
    75  		if err != nil {
    76  			return nil, newErrorConflict(o.key, types.ID(0), "Server is not found")
    77  		}
    78  		server.Disks = append(server.Disks, &iaas.ServerConnectedDisk{
    79  			ID:              result.ID,
    80  			Name:            result.Name,
    81  			Availability:    result.Availability,
    82  			Connection:      result.Connection,
    83  			ConnectionOrder: result.ConnectionOrder,
    84  			ReinstallCount:  result.ReinstallCount,
    85  			SizeMB:          result.SizeMB,
    86  			DiskPlanID:      result.DiskPlanID,
    87  			Storage:         result.Storage,
    88  		})
    89  		putServer(zone, server)
    90  	}
    91  
    92  	putDisk(zone, result)
    93  
    94  	id := result.ID
    95  	startDiskCopy(o.key, zone, func() (interface{}, error) {
    96  		disk, err := o.Read(context.Background(), zone, id)
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  		return disk, nil
   101  	})
   102  
   103  	return result, nil
   104  }
   105  
   106  // Config is fake implementation
   107  func (o *DiskOp) Config(ctx context.Context, zone string, id types.ID, edit *iaas.DiskEditRequest) error {
   108  	disk, err := o.Read(ctx, zone, id)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	if disk.ServerID.IsEmpty() {
   113  		return nil
   114  	}
   115  
   116  	serverOp := NewServerOp()
   117  	server, err := serverOp.Read(ctx, zone, disk.ServerID)
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	if edit.HostName != "" {
   123  		server.HostName = edit.HostName
   124  		putServer(zone, server)
   125  	}
   126  
   127  	if len(server.Interfaces) > 0 {
   128  		nic := server.Interfaces[0]
   129  		if nic.SwitchScope == types.Scopes.Shared {
   130  			nic.IPAddress = pool().nextSharedIP().String()
   131  		} else {
   132  			nic.UserIPAddress = edit.UserIPAddress
   133  		}
   134  
   135  		swOp := NewSwitchOp()
   136  		sw, err := swOp.Read(ctx, zone, nic.SwitchID)
   137  		if err != nil {
   138  			return err
   139  		}
   140  
   141  		if len(sw.Subnets) == 0 {
   142  			nic.UserSubnetDefaultRoute = edit.UserSubnet.DefaultRoute
   143  			nic.UserSubnetNetworkMaskLen = edit.UserSubnet.NetworkMaskLen
   144  		} else {
   145  			nic.UserSubnetDefaultRoute = sw.Subnets[0].DefaultRoute
   146  			nic.UserSubnetNetworkMaskLen = sw.Subnets[0].NetworkMaskLen
   147  			nic.SubnetDefaultRoute = sw.Subnets[0].DefaultRoute
   148  			nic.SubnetNetworkAddress = sw.Subnets[0].NetworkAddress
   149  		}
   150  
   151  		putServer(zone, server)
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  // CreateWithConfig is fake implementation
   158  func (o *DiskOp) CreateWithConfig(ctx context.Context, zone string, createParam *iaas.DiskCreateRequest, editParam *iaas.DiskEditRequest, bootAtAvailable bool, distantFrom []types.ID) (*iaas.Disk, error) {
   159  	// check
   160  	if !createParam.ServerID.IsEmpty() {
   161  		serverOp := NewServerOp()
   162  		_, err := serverOp.Read(ctx, zone, createParam.ServerID)
   163  		if err != nil {
   164  			return nil, newErrorBadRequest(o.key, types.ID(0), fmt.Sprintf("Server %s is not found", createParam.ServerID))
   165  		}
   166  	}
   167  
   168  	result, err := o.Create(ctx, zone, createParam, distantFrom)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  
   173  	if err := o.Config(ctx, zone, result.ID, editParam); err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	if !createParam.ServerID.IsEmpty() && bootAtAvailable {
   178  		waiter := iaas.WaiterForReady(func() (interface{}, error) {
   179  			disk, err := o.Read(ctx, zone, result.ID)
   180  			if err != nil {
   181  				return nil, err
   182  			}
   183  			return disk, nil
   184  		})
   185  		res, err := waiter.WaitForState(ctx)
   186  		if err != nil {
   187  			return nil, err
   188  		}
   189  		result = res.(*iaas.Disk)
   190  
   191  		// boot server
   192  		serverOp := NewServerOp()
   193  		if err := serverOp.Boot(ctx, zone, createParam.ServerID); err != nil {
   194  			return nil, err
   195  		}
   196  	}
   197  	return result, nil
   198  }
   199  
   200  // ResizePartition is fake implementation
   201  func (o *DiskOp) ResizePartition(ctx context.Context, zone string, id types.ID, param *iaas.DiskResizePartitionRequest) error {
   202  	_, err := o.Read(ctx, zone, id)
   203  	if err != nil {
   204  		return err
   205  	}
   206  	return nil
   207  }
   208  
   209  // ConnectToServer is fake implementation
   210  func (o *DiskOp) ConnectToServer(ctx context.Context, zone string, id types.ID, serverID types.ID) error {
   211  	value, err := o.Read(ctx, zone, id)
   212  	if err != nil {
   213  		return err
   214  	}
   215  
   216  	serverOp := NewServerOp()
   217  	server, err := serverOp.Read(ctx, zone, serverID)
   218  	if err != nil {
   219  		return newErrorBadRequest(o.key, id, fmt.Sprintf("Server[%d] is not exists", serverID))
   220  	}
   221  
   222  	for _, connected := range server.Disks {
   223  		if connected.ID == value.ID {
   224  			return newErrorBadRequest(o.key, id, fmt.Sprintf("Disk[%d] is already connected to Server[%d]", id, serverID))
   225  		}
   226  	}
   227  
   228  	// TODO とりあえず同時実行制御は考慮しない。更新対象リソースが増えるようであれば実装方法を考える
   229  
   230  	connectedDisk := &iaas.ServerConnectedDisk{}
   231  	copySameNameField(value, connectedDisk)
   232  	server.Disks = append(server.Disks, connectedDisk)
   233  	putServer(zone, server)
   234  	value.ServerID = serverID
   235  	value.ServerName = server.Name
   236  	putDisk(zone, value)
   237  
   238  	return nil
   239  }
   240  
   241  // DisconnectFromServer is fake implementation
   242  func (o *DiskOp) DisconnectFromServer(ctx context.Context, zone string, id types.ID) error {
   243  	value, err := o.Read(ctx, zone, id)
   244  	if err != nil {
   245  		return err
   246  	}
   247  
   248  	if value.ServerID.IsEmpty() {
   249  		return newErrorBadRequest(o.key, id, fmt.Sprintf("Disk[%d] is not connected to Server", id))
   250  	}
   251  
   252  	serverOp := NewServerOp()
   253  	server, err := serverOp.Read(ctx, zone, value.ServerID)
   254  	if err != nil {
   255  		return newErrorBadRequest(o.key, id, fmt.Sprintf("Server[%d] is not exists", value.ServerID))
   256  	}
   257  
   258  	var disks []*iaas.ServerConnectedDisk
   259  	for _, connected := range server.Disks {
   260  		if connected.ID != value.ID {
   261  			connectedDisk := &iaas.ServerConnectedDisk{}
   262  			copySameNameField(value, connectedDisk)
   263  			server.Disks = append(server.Disks, connectedDisk)
   264  			disks = append(disks, connected)
   265  		}
   266  	}
   267  	if len(disks) == len(server.Disks) {
   268  		return newInternalServerError(o.key, id, fmt.Sprintf("Disk[%d] is not found on server's connected disks", id))
   269  	}
   270  
   271  	server.Disks = disks
   272  	putServer(zone, server)
   273  	value.ServerID = types.ID(0)
   274  	value.ServerName = ""
   275  	putDisk(zone, value)
   276  
   277  	return nil
   278  }
   279  
   280  // Read is fake implementation
   281  func (o *DiskOp) Read(ctx context.Context, zone string, id types.ID) (*iaas.Disk, error) {
   282  	value := getDiskByID(zone, id)
   283  	if value == nil {
   284  		return nil, newErrorNotFound(o.key, id)
   285  	}
   286  
   287  	dest := &iaas.Disk{}
   288  	copySameNameField(value, dest)
   289  	return dest, nil
   290  }
   291  
   292  // Update is fake implementation
   293  func (o *DiskOp) Update(ctx context.Context, zone string, id types.ID, param *iaas.DiskUpdateRequest) (*iaas.Disk, error) {
   294  	value, err := o.Read(ctx, zone, id)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	copySameNameField(param, value)
   299  	fill(value, fillModifiedAt)
   300  
   301  	putDisk(zone, value)
   302  	return value, nil
   303  }
   304  
   305  // Delete is fake implementation
   306  func (o *DiskOp) Delete(ctx context.Context, zone string, id types.ID) error {
   307  	_, err := o.Read(ctx, zone, id)
   308  	if err != nil {
   309  		return err
   310  	}
   311  	ds().Delete(o.key, zone, id)
   312  	return nil
   313  }
   314  
   315  // Monitor is fake implementation
   316  func (o *DiskOp) Monitor(ctx context.Context, zone string, id types.ID, condition *iaas.MonitorCondition) (*iaas.DiskActivity, error) {
   317  	_, err := o.Read(ctx, zone, id)
   318  	if err != nil {
   319  		return nil, err
   320  	}
   321  	now := time.Now().Truncate(time.Second)
   322  	m := now.Minute() % 5
   323  	if m != 0 {
   324  		now.Add(time.Duration(m) * time.Minute)
   325  	}
   326  
   327  	res := &iaas.DiskActivity{}
   328  	for i := 0; i < 5; i++ {
   329  		res.Values = append(res.Values, &iaas.MonitorDiskValue{
   330  			Time:  now.Add(time.Duration(i*-5) * time.Minute),
   331  			Read:  float64(random(1000)),
   332  			Write: float64(random(1000)),
   333  		})
   334  	}
   335  
   336  	return res, nil
   337  }
   338  
   339  // MonitorDisk is fake implementation
   340  func (o *DiskOp) MonitorDisk(ctx context.Context, zone string, id types.ID, condition *iaas.MonitorCondition) (*iaas.DiskActivity, error) {
   341  	return o.Monitor(ctx, zone, id, condition)
   342  }