github.com/sacloud/iaas-api-go@v1.12.0/fake/ops_server.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 *ServerOp) Find(ctx context.Context, zone string, conditions *iaas.FindCondition) (*iaas.ServerFindResult, error) { 28 results, _ := find(o.key, zone, conditions) 29 var values []*iaas.Server 30 for _, res := range results { 31 dest := &iaas.Server{} 32 copySameNameField(res, dest) 33 values = append(values, dest) 34 } 35 return &iaas.ServerFindResult{ 36 Total: len(results), 37 Count: len(results), 38 From: 0, 39 Servers: values, 40 }, nil 41 } 42 43 // Create is fake implementation 44 func (o *ServerOp) Create(ctx context.Context, zone string, param *iaas.ServerCreateRequest) (*iaas.Server, error) { 45 result := &iaas.Server{} 46 copySameNameField(param, result) 47 fill(result, fillID, fillCreatedAt) 48 49 result.Availability = types.Availabilities.Migrating 50 if param.ServerPlanGeneration == types.PlanGenerations.Default { 51 switch zone { 52 case "is1a": 53 result.ServerPlanGeneration = types.PlanGenerations.G200 54 default: 55 result.ServerPlanGeneration = types.PlanGenerations.G100 56 } 57 } 58 // TODO プランAPIを実装したら修正する 59 result.ServerPlanID = types.StringID(fmt.Sprintf("%03d%03d%03d", result.ServerPlanGeneration, result.GetMemoryGB(), result.CPU)) 60 result.ServerPlanName = fmt.Sprintf("世代:%03d メモリ:%03d CPU:%03d", result.ServerPlanGeneration, result.GetMemoryGB(), result.CPU) 61 62 // NIC操作のためにあらかじめ登録しておく 63 putServer(zone, result) 64 65 for _, cs := range param.ConnectedSwitches { 66 ifOp := NewInterfaceOp() 67 swOp := NewSwitchOp() 68 69 ifCreateParam := &iaas.InterfaceCreateRequest{} 70 if cs != nil { 71 if cs.Scope != types.Scopes.Shared { 72 _, err := swOp.Read(ctx, zone, cs.ID) 73 if err != nil { 74 return nil, newErrorConflict(o.key, types.ID(0), err.Error()) 75 } 76 } 77 ifCreateParam.ServerID = result.ID 78 } 79 80 iface, err := ifOp.Create(ctx, zone, ifCreateParam) 81 if err != nil { 82 return nil, newErrorConflict(o.key, types.ID(0), err.Error()) 83 } 84 85 if cs != nil { 86 if cs.Scope == types.Scopes.Shared { 87 if err := ifOp.ConnectToSharedSegment(ctx, zone, iface.ID); err != nil { 88 return nil, newErrorConflict(o.key, types.ID(0), err.Error()) 89 } 90 } else { 91 if err := ifOp.ConnectToSwitch(ctx, zone, iface.ID, cs.ID); err != nil { 92 return nil, newErrorConflict(o.key, types.ID(0), err.Error()) 93 } 94 } 95 } 96 97 iface, err = ifOp.Read(ctx, zone, iface.ID) 98 if err != nil { 99 return nil, newErrorConflict(o.key, types.ID(0), err.Error()) 100 } 101 ifaceView := &iaas.InterfaceView{} 102 copySameNameField(iface, ifaceView) 103 104 // note: UserIPAddressとIPAddressはディスクの修正にて設定されるためここでは空となる。 105 if cs != nil { 106 if cs.Scope == types.Scopes.Shared { 107 ifaceView.SwitchScope = sharedSegmentSwitch.Scope 108 ifaceView.SwitchID = sharedSegmentSwitch.ID 109 ifaceView.SwitchName = sharedSegmentSwitch.Name 110 111 if len(sharedSegmentSwitch.Subnets) > 0 { 112 ifaceView.UserSubnetDefaultRoute = sharedSegmentSwitch.Subnets[0].DefaultRoute 113 ifaceView.UserSubnetNetworkMaskLen = sharedSegmentSwitch.Subnets[0].NetworkMaskLen 114 ifaceView.SubnetDefaultRoute = sharedSegmentSwitch.Subnets[0].DefaultRoute 115 ifaceView.SubnetNetworkAddress = sharedSegmentSwitch.Subnets[0].NetworkAddress 116 } 117 } else { 118 ifaceView.SwitchScope = types.Scopes.User 119 ifaceView.SwitchID = cs.ID 120 121 sw, err := swOp.Read(ctx, zone, cs.ID) 122 if err != nil { 123 return nil, err 124 } 125 if len(sw.Subnets) > 0 { 126 ifaceView.UserSubnetDefaultRoute = sw.Subnets[0].DefaultRoute 127 ifaceView.UserSubnetNetworkMaskLen = sw.Subnets[0].NetworkMaskLen 128 ifaceView.SubnetDefaultRoute = sw.Subnets[0].DefaultRoute 129 ifaceView.SubnetNetworkAddress = sw.Subnets[0].NetworkAddress 130 } 131 } 132 } 133 134 result.Interfaces = append(result.Interfaces, ifaceView) 135 } 136 zoneOp := NewZoneOp() 137 zones, _ := zoneOp.Find(ctx, nil) 138 for _, z := range zones.Zones { 139 if zone == z.Name { 140 zoneInfo := &iaas.ZoneInfo{} 141 copySameNameField(z, zoneInfo) 142 result.Zone = zoneInfo 143 } 144 } 145 146 result.Availability = types.Availabilities.Available 147 putServer(zone, result) 148 return result, nil 149 } 150 151 // Read is fake implementation 152 func (o *ServerOp) Read(ctx context.Context, zone string, id types.ID) (*iaas.Server, error) { 153 value := getServerByID(zone, id) 154 if value == nil { 155 return nil, newErrorNotFound(o.key, id) 156 } 157 158 dest := &iaas.Server{} 159 copySameNameField(value, dest) 160 return dest, nil 161 } 162 163 // Update is fake implementation 164 func (o *ServerOp) Update(ctx context.Context, zone string, id types.ID, param *iaas.ServerUpdateRequest) (*iaas.Server, error) { 165 value, err := o.Read(ctx, zone, id) 166 if err != nil { 167 return nil, err 168 } 169 170 copySameNameField(param, value) 171 fill(value, fillModifiedAt) 172 173 putServer(zone, value) 174 return value, nil 175 } 176 177 // Delete is fake implementation 178 func (o *ServerOp) Delete(ctx context.Context, zone string, id types.ID) error { 179 value, err := o.Read(ctx, zone, id) 180 if err != nil { 181 return err 182 } 183 184 if value.InstanceStatus.IsUp() { 185 return newErrorConflict(o.key, id, fmt.Sprintf("Server[%s] is still running", id)) 186 } 187 188 ifOp := NewInterfaceOp() 189 for _, iface := range value.Interfaces { 190 if err := ifOp.Delete(ctx, zone, iface.ID); err != nil { 191 return err 192 } 193 } 194 195 diskOp := NewDiskOp() 196 for _, disk := range value.Disks { 197 if err := diskOp.DisconnectFromServer(ctx, zone, disk.ID); err != nil { 198 return err 199 } 200 } 201 202 ds().Delete(o.key, zone, id) 203 return nil 204 } 205 206 // DeleteWithDisks is fake implementation 207 func (o *ServerOp) DeleteWithDisks(ctx context.Context, zone string, id types.ID, disks *iaas.ServerDeleteWithDisksRequest) error { 208 if err := o.Delete(ctx, zone, id); err != nil { 209 return err 210 } 211 diskOp := NewDiskOp() 212 for _, diskID := range disks.IDs { 213 if err := diskOp.Delete(ctx, zone, diskID); err != nil { 214 return err 215 } 216 } 217 return nil 218 } 219 220 // ChangePlan is fake implementation 221 func (o *ServerOp) ChangePlan(ctx context.Context, zone string, id types.ID, plan *iaas.ServerChangePlanRequest) (*iaas.Server, error) { 222 value, err := o.Read(ctx, zone, id) 223 if err != nil { 224 return nil, err 225 } 226 227 if value.InstanceStatus.IsUp() { 228 return nil, newErrorConflict(o.key, id, fmt.Sprintf("Server[%d] is running", value.ID)) 229 } 230 231 value.CPU = plan.CPU 232 value.MemoryMB = plan.MemoryMB 233 value.ServerPlanCPUModel = plan.ServerPlanCPUModel 234 if value.ServerPlanCPUModel == "" { 235 value.ServerPlanCPUModel = "uncategorized" 236 } 237 value.ServerPlanCommitment = plan.ServerPlanCommitment 238 value.ServerPlanGeneration = plan.ServerPlanGeneration 239 value.ServerPlanID = types.StringID(fmt.Sprintf("%03d%03d%03d", value.ServerPlanGeneration, value.GetMemoryGB(), value.CPU)) 240 value.ServerPlanName = fmt.Sprintf("世代:%03d メモリ:%03d CPU:%03d", value.ServerPlanGeneration, value.GetMemoryGB(), value.CPU) 241 242 // ID変更 243 ds().Delete(o.key, zone, value.ID) 244 newServer := &iaas.Server{} 245 copySameNameField(value, newServer) 246 newServer.ID = pool().generateID() 247 putServer(zone, newServer) 248 249 // DiskのServerIDも変更 250 searched, _ := NewDiskOp().Find(ctx, zone, nil) 251 for _, disk := range searched.Disks { 252 if disk.ServerID == value.ID { 253 disk.ServerID = newServer.ID 254 putDisk(zone, disk) 255 } 256 } 257 for _, nic := range newServer.Interfaces { 258 iface, err := NewInterfaceOp().Read(ctx, zone, nic.ID) 259 if err == nil { 260 iface.ServerID = newServer.ID 261 putInterface(zone, iface) 262 } 263 } 264 265 return newServer, nil 266 } 267 268 // InsertCDROM is fake implementation 269 func (o *ServerOp) InsertCDROM(ctx context.Context, zone string, id types.ID, insertParam *iaas.InsertCDROMRequest) error { 270 value, err := o.Read(ctx, zone, id) 271 if err != nil { 272 return err 273 } 274 275 cdromOp := NewCDROMOp() 276 if _, err = cdromOp.Read(ctx, zone, insertParam.ID); err != nil { 277 return newErrorBadRequest(o.key, id, fmt.Sprintf("CDROM[%d] is not exists", insertParam.ID)) 278 } 279 280 value.CDROMID = insertParam.ID 281 putServer(zone, value) 282 return nil 283 } 284 285 // EjectCDROM is fake implementation 286 func (o *ServerOp) EjectCDROM(ctx context.Context, zone string, id types.ID, insertParam *iaas.EjectCDROMRequest) error { 287 value, err := o.Read(ctx, zone, id) 288 if err != nil { 289 return err 290 } 291 292 cdromOp := NewCDROMOp() 293 if _, err = cdromOp.Read(ctx, zone, insertParam.ID); err != nil { 294 return newErrorBadRequest(o.key, id, fmt.Sprintf("CDROM[%d] is not exists", insertParam.ID)) 295 } 296 297 value.CDROMID = types.ID(0) 298 putServer(zone, value) 299 return nil 300 } 301 302 // Boot is fake implementation 303 func (o *ServerOp) Boot(ctx context.Context, zone string, id types.ID) error { 304 value, err := o.Read(ctx, zone, id) 305 if err != nil { 306 return err 307 } 308 if value.InstanceStatus.IsUp() { 309 return newErrorConflict(o.key, id, "Boot is failed") 310 } 311 312 startPowerOn(o.key, zone, func() (interface{}, error) { 313 return o.Read(context.Background(), zone, id) 314 }) 315 316 return err 317 } 318 319 // BootWithVariables is fake implementation 320 func (o *ServerOp) BootWithVariables(ctx context.Context, zone string, id types.ID, param *iaas.ServerBootVariables) error { 321 return o.Boot(ctx, zone, id) // paramは非対応 322 } 323 324 // Shutdown is fake implementation 325 func (o *ServerOp) Shutdown(ctx context.Context, zone string, id types.ID, shutdownOption *iaas.ShutdownOption) error { 326 value, err := o.Read(ctx, zone, id) 327 if err != nil { 328 return err 329 } 330 if !value.InstanceStatus.IsUp() { 331 return newErrorConflict(o.key, id, "Shutdown is failed") 332 } 333 334 startPowerOff(o.key, zone, func() (interface{}, error) { 335 return o.Read(context.Background(), zone, id) 336 }) 337 338 return err 339 } 340 341 // Reset is fake implementation 342 func (o *ServerOp) Reset(ctx context.Context, zone string, id types.ID) error { 343 value, err := o.Read(ctx, zone, id) 344 if err != nil { 345 return err 346 } 347 if !value.InstanceStatus.IsUp() { 348 return newErrorConflict(o.key, id, "Reset is failed") 349 } 350 351 startPowerOn(o.key, zone, func() (interface{}, error) { 352 return o.Read(context.Background(), zone, id) 353 }) 354 355 return nil 356 } 357 358 // SendKey is fake implementation 359 func (o *ServerOp) SendKey(ctx context.Context, zone string, id types.ID, keyboardParam *iaas.SendKeyRequest) error { 360 _, err := o.Read(ctx, zone, id) 361 if err != nil { 362 return err 363 } 364 return nil 365 } 366 367 // SendNMI is fake implementation 368 func (o *ServerOp) SendNMI(ctx context.Context, zone string, id types.ID) error { 369 _, err := o.Read(ctx, zone, id) 370 if err != nil { 371 return err 372 } 373 return nil 374 } 375 376 // GetVNCProxy is fake implementation 377 func (o *ServerOp) GetVNCProxy(ctx context.Context, zone string, id types.ID) (*iaas.VNCProxyInfo, error) { 378 _, err := o.Read(ctx, zone, id) 379 if err != nil { 380 return nil, err 381 } 382 vncFileTemplate := `[connection] 383 host=sac-%s-vnc.cloud.sakura.ad.jp 384 port=51234 385 password=aaabababababa` 386 387 return &iaas.VNCProxyInfo{ 388 Status: "OK", 389 Host: "localhost", 390 IOServerHost: fmt.Sprintf("sac-%s-vnc.cloud.sakura.ad.jp", zone), 391 Port: 51234, 392 Password: "dummy", 393 VNCFile: fmt.Sprintf(vncFileTemplate, zone), 394 }, nil 395 } 396 397 // Monitor is fake implementation 398 func (o *ServerOp) Monitor(ctx context.Context, zone string, id types.ID, condition *iaas.MonitorCondition) (*iaas.CPUTimeActivity, error) { 399 value, err := o.Read(ctx, zone, id) 400 if err != nil { 401 return nil, err 402 } 403 404 now := time.Now().Truncate(time.Second) 405 m := now.Minute() % 5 406 if m != 0 { 407 now.Add(time.Duration(m) * time.Minute) 408 } 409 410 res := &iaas.CPUTimeActivity{} 411 for i := 0; i < 5; i++ { 412 res.Values = append(res.Values, &iaas.MonitorCPUTimeValue{ 413 Time: now.Add(time.Duration(i*-5) * time.Minute), 414 CPUTime: float64(random(value.CPU * 1000)), 415 }) 416 } 417 418 return res, nil 419 } 420 421 // MonitorCPU is fake implementation 422 func (o *ServerOp) MonitorCPU(ctx context.Context, zone string, id types.ID, condition *iaas.MonitorCondition) (*iaas.CPUTimeActivity, error) { 423 return o.Monitor(ctx, zone, id, condition) 424 }