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 }