github.com/sacloud/iaas-api-go@v1.12.0/testutil/cleanup.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 testutil
    16  
    17  import (
    18  	"context"
    19  	"sync"
    20  
    21  	"github.com/hashicorp/go-multierror"
    22  	"github.com/sacloud/iaas-api-go"
    23  	"github.com/sacloud/iaas-api-go/search"
    24  	"github.com/sacloud/iaas-api-go/types"
    25  )
    26  
    27  func ComposeCleanupFuncs(funcs ...func(context.Context, iaas.APICaller) error) func(context.Context, iaas.APICaller) error {
    28  	return func(ctx context.Context, caller iaas.APICaller) error {
    29  		for _, f := range funcs {
    30  			if err := f(ctx, caller); err != nil {
    31  				return err
    32  			}
    33  		}
    34  		return nil
    35  	}
    36  }
    37  
    38  func ComposeCleanupResourceFunc(prefix string, targets ...CleanupTarget) func(context.Context, iaas.APICaller) error {
    39  	var funcs []func(context.Context, iaas.APICaller) error
    40  	for _, t := range targets {
    41  		funcs = append(funcs, func(ctx context.Context, caller iaas.APICaller) error {
    42  			return CleanupResource(ctx, caller, prefix, t)
    43  		})
    44  	}
    45  	return ComposeCleanupFuncs(funcs...)
    46  }
    47  
    48  func CleanupResource(ctx context.Context, caller iaas.APICaller, prefix string, target CleanupTarget) error {
    49  	if !IsAccTest() {
    50  		return nil
    51  	}
    52  	if prefix == "" {
    53  		prefix = TestResourcePrefix
    54  	}
    55  	cleanupFindCondition = &iaas.FindCondition{
    56  		Filter: search.Filter{
    57  			search.Key("Name"): search.PartialMatch(prefix),
    58  		},
    59  	}
    60  
    61  	searched, err := target.finder(ctx, caller)
    62  	if err != nil {
    63  		return err
    64  	}
    65  
    66  	var errs *multierror.Error
    67  	var wg sync.WaitGroup
    68  	for i := range searched {
    69  		wg.Add(1)
    70  		go func(target *cleanupTarget) {
    71  			defer wg.Done()
    72  			if target.prepareFunc != nil {
    73  				if err := target.prepareFunc(ctx); err != nil {
    74  					multierror.Append(errs, err) //nolint
    75  					return
    76  				}
    77  			}
    78  			if target.deleteFunc != nil {
    79  				if err := target.deleteFunc(ctx); err != nil {
    80  					multierror.Append(errs, err) //nolint
    81  					return
    82  				}
    83  			}
    84  		}(searched[i])
    85  	}
    86  	wg.Wait()
    87  
    88  	return errs.ErrorOrNil()
    89  }
    90  
    91  type CleanupTarget struct {
    92  	finder cleanupTargetFindFunc
    93  }
    94  
    95  // CleanupTargets クリーンアップ対象のリソース。CleanupResourceに渡す
    96  var CleanupTargets = struct {
    97  	Archive           CleanupTarget
    98  	AutoBackup        CleanupTarget
    99  	Bridge            CleanupTarget
   100  	ContainerRegistry CleanupTarget
   101  	CDROM             CleanupTarget
   102  	Database          CleanupTarget
   103  	Disk              CleanupTarget
   104  	DNS               CleanupTarget
   105  	GSLB              CleanupTarget
   106  	Icon              CleanupTarget
   107  	Internet          CleanupTarget
   108  	License           CleanupTarget
   109  	LoadBalancer      CleanupTarget
   110  	MobileGateway     CleanupTarget
   111  	NFS               CleanupTarget
   112  	Note              CleanupTarget
   113  	PacketFilter      CleanupTarget
   114  	PrivateHost       CleanupTarget
   115  	ProxyLB           CleanupTarget
   116  	Server            CleanupTarget
   117  	SIM               CleanupTarget
   118  	SimpleMonitor     CleanupTarget
   119  	SSHKey            CleanupTarget
   120  	Switch            CleanupTarget
   121  	VPCRouter         CleanupTarget
   122  }{
   123  	Archive:           CleanupTarget{finder: findArchive},
   124  	AutoBackup:        CleanupTarget{finder: findAutoBackup},
   125  	Bridge:            CleanupTarget{finder: findBridge},
   126  	ContainerRegistry: CleanupTarget{finder: findContainerRegistry},
   127  	CDROM:             CleanupTarget{finder: findCDROM},
   128  	Database:          CleanupTarget{finder: findDatabase},
   129  	Disk:              CleanupTarget{finder: findDisk},
   130  	DNS:               CleanupTarget{finder: findDNS},
   131  	GSLB:              CleanupTarget{finder: findGSLB},
   132  	Icon:              CleanupTarget{finder: findIcon},
   133  	Internet:          CleanupTarget{finder: findInternet},
   134  	License:           CleanupTarget{finder: findLicense},
   135  	LoadBalancer:      CleanupTarget{finder: findLoadBalancer},
   136  	MobileGateway:     CleanupTarget{finder: findMobileGateway},
   137  	NFS:               CleanupTarget{finder: findNFS},
   138  	Note:              CleanupTarget{finder: findNote},
   139  	PacketFilter:      CleanupTarget{finder: findPacketFilter},
   140  	PrivateHost:       CleanupTarget{finder: findPrivateHost},
   141  	ProxyLB:           CleanupTarget{finder: findProxyLB},
   142  	Server:            CleanupTarget{finder: findServer},
   143  	SIM:               CleanupTarget{finder: findSIM},
   144  	SimpleMonitor:     CleanupTarget{finder: findSimpleMonitor},
   145  	SSHKey:            CleanupTarget{finder: findSSHKey},
   146  	Switch:            CleanupTarget{finder: findSwitch},
   147  	VPCRouter:         CleanupTarget{finder: findVPCRouter},
   148  }
   149  
   150  // CleanupTestResources 指定プレフィックスを持つリソースの削除を行う
   151  //
   152  // TESTACC環境変数が設定されている場合のみ実施される
   153  func CleanupTestResources(ctx context.Context, caller iaas.APICaller) error {
   154  	if !IsAccTest() {
   155  		return nil
   156  	}
   157  	cleanupFindCondition = &iaas.FindCondition{
   158  		Filter: search.Filter{
   159  			search.Key("Name"): search.PartialMatch(TestResourcePrefix),
   160  		},
   161  	}
   162  	var errs *multierror.Error
   163  
   164  	// cleanup: primary group
   165  	doCleanup(ctx, correctCleanupTargets(ctx, caller, cleanupPrimaryGroup, errs), errs)
   166  	// cleanup: secondary group
   167  	doCleanup(ctx, correctCleanupTargets(ctx, caller, cleanupSecondaryGroup, errs), errs)
   168  
   169  	return errs.ErrorOrNil()
   170  }
   171  
   172  func doCleanup(ctx context.Context, targets []*cleanupTarget, errs *multierror.Error) {
   173  	var wg sync.WaitGroup
   174  	for i := range targets {
   175  		wg.Add(1)
   176  		go func(target *cleanupTarget) {
   177  			defer wg.Done()
   178  			if target.prepareFunc != nil {
   179  				if err := target.prepareFunc(ctx); err != nil {
   180  					multierror.Append(errs, err) //nolint
   181  					return
   182  				}
   183  			}
   184  			if target.deleteFunc != nil {
   185  				if err := target.deleteFunc(ctx); err != nil {
   186  					multierror.Append(errs, err) //nolint
   187  					return
   188  				}
   189  			}
   190  		}(targets[i])
   191  	}
   192  	wg.Wait()
   193  }
   194  
   195  func correctCleanupTargets(ctx context.Context, caller iaas.APICaller, finders []cleanupTargetFindFunc, errs *multierror.Error) []*cleanupTarget {
   196  	var targets []*cleanupTarget
   197  	var wg sync.WaitGroup
   198  	for i := range finders {
   199  		wg.Add(1)
   200  		go func(finder cleanupTargetFindFunc) {
   201  			defer wg.Done()
   202  
   203  			res, err := finder(ctx, caller)
   204  			if err != nil {
   205  				multierror.Append(errs, err) //nolint
   206  				return
   207  			}
   208  			targets = append(targets, res...)
   209  		}(finders[i])
   210  	}
   211  	wg.Wait()
   212  	return targets
   213  }
   214  
   215  type cleanupTargetFindFunc func(context.Context, iaas.APICaller) ([]*cleanupTarget, error)
   216  
   217  var cleanupPrimaryGroup = []cleanupTargetFindFunc{
   218  	findArchive,
   219  	findAutoBackup,
   220  	findContainerRegistry,
   221  	findDatabase,
   222  	findDNS,
   223  	findGSLB,
   224  	findIcon,
   225  	findLicense,
   226  	findLoadBalancer,
   227  	findNFS,
   228  	findNote,
   229  	findPacketFilter,
   230  	findProxyLB,
   231  	findServer,
   232  	findSimpleMonitor,
   233  	findSSHKey,
   234  	findVPCRouter,
   235  	findMobileGateway,
   236  }
   237  
   238  var cleanupSecondaryGroup = []cleanupTargetFindFunc{
   239  	findBridge,
   240  	findCDROM,
   241  	findDisk,
   242  	findInternet,
   243  	findSwitch,
   244  	findPrivateHost,
   245  	findSIM,
   246  }
   247  
   248  var cleanupFindCondition = &iaas.FindCondition{
   249  	Filter: search.Filter{
   250  		search.Key("Name"): search.PartialMatch(TestResourcePrefix),
   251  	},
   252  }
   253  
   254  type cleanupTarget struct {
   255  	resource    interface{}
   256  	prepareFunc func(context.Context) error
   257  	deleteFunc  func(context.Context) error
   258  }
   259  
   260  func findBridge(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   261  	op := iaas.NewBridgeOp(caller)
   262  	searched, err := op.Find(ctx, iaas.APIDefaultZone, cleanupFindCondition)
   263  	if err != nil {
   264  		return nil, err
   265  	}
   266  	var res []*cleanupTarget
   267  	for i := range searched.Bridges {
   268  		v := searched.Bridges[i]
   269  		res = append(res, &cleanupTarget{
   270  			resource: v,
   271  			deleteFunc: func(ctx context.Context) error {
   272  				return op.Delete(ctx, iaas.APIDefaultZone, v.ID)
   273  			},
   274  		})
   275  	}
   276  	return res, nil
   277  }
   278  
   279  func findContainerRegistry(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   280  	op := iaas.NewContainerRegistryOp(caller)
   281  	searched, err := op.Find(ctx, cleanupFindCondition)
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  	var res []*cleanupTarget
   286  	for i := range searched.ContainerRegistries {
   287  		v := searched.ContainerRegistries[i]
   288  		res = append(res, &cleanupTarget{
   289  			resource: v,
   290  			deleteFunc: func(ctx context.Context) error {
   291  				return op.Delete(ctx, v.ID)
   292  			},
   293  		})
   294  	}
   295  	return res, nil
   296  }
   297  
   298  func findCDROM(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   299  	op := iaas.NewCDROMOp(caller)
   300  	var res []*cleanupTarget
   301  
   302  	for i := range types.ZoneNames {
   303  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   304  		if err != nil {
   305  			return nil, err
   306  		}
   307  		zone := types.ZoneNames[i]
   308  		for j := range searched.CDROMs {
   309  			v := searched.CDROMs[j]
   310  			res = append(res, &cleanupTarget{
   311  				resource: v,
   312  				deleteFunc: func(ctx context.Context) error {
   313  					return op.Delete(ctx, zone, v.ID)
   314  				},
   315  			})
   316  		}
   317  	}
   318  	return res, nil
   319  }
   320  
   321  func findInternet(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   322  	op := iaas.NewInternetOp(caller)
   323  	var res []*cleanupTarget
   324  
   325  	for i := range types.ZoneNames {
   326  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   327  		if err != nil {
   328  			return nil, err
   329  		}
   330  		zone := types.ZoneNames[i]
   331  		for j := range searched.Internet {
   332  			v := searched.Internet[j]
   333  			res = append(res, &cleanupTarget{
   334  				resource: v,
   335  				deleteFunc: func(ctx context.Context) error {
   336  					return op.Delete(ctx, zone, v.ID)
   337  				},
   338  			})
   339  		}
   340  	}
   341  	return res, nil
   342  }
   343  
   344  func findSwitch(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   345  	op := iaas.NewSwitchOp(caller)
   346  	var res []*cleanupTarget
   347  
   348  	for i := range types.ZoneNames {
   349  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   350  		if err != nil {
   351  			return nil, err
   352  		}
   353  		zone := types.ZoneNames[i]
   354  		for j := range searched.Switches {
   355  			v := searched.Switches[j]
   356  			res = append(res, &cleanupTarget{
   357  				resource: v,
   358  				deleteFunc: func(ctx context.Context) error {
   359  					return op.Delete(ctx, zone, v.ID)
   360  				},
   361  			})
   362  		}
   363  	}
   364  	return res, nil
   365  }
   366  
   367  func findPrivateHost(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   368  	op := iaas.NewPrivateHostOp(caller)
   369  	var res []*cleanupTarget
   370  
   371  	for i := range types.ZoneNames {
   372  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   373  		if err != nil {
   374  			return nil, err
   375  		}
   376  		zone := types.ZoneNames[i]
   377  		for j := range searched.PrivateHosts {
   378  			v := searched.PrivateHosts[j]
   379  			res = append(res, &cleanupTarget{
   380  				resource: v,
   381  				deleteFunc: func(ctx context.Context) error {
   382  					return op.Delete(ctx, zone, v.ID)
   383  				},
   384  			})
   385  		}
   386  	}
   387  	return res, nil
   388  }
   389  
   390  func findArchive(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   391  	op := iaas.NewArchiveOp(caller)
   392  	var res []*cleanupTarget
   393  
   394  	for i := range types.ZoneNames {
   395  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   396  		if err != nil {
   397  			return nil, err
   398  		}
   399  		zone := types.ZoneNames[i]
   400  		for j := range searched.Archives {
   401  			v := searched.Archives[j]
   402  			res = append(res, &cleanupTarget{
   403  				resource: v,
   404  				deleteFunc: func(ctx context.Context) error {
   405  					return op.Delete(ctx, zone, v.ID)
   406  				},
   407  			})
   408  		}
   409  	}
   410  	return res, nil
   411  }
   412  
   413  func findAutoBackup(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   414  	op := iaas.NewAutoBackupOp(caller)
   415  	var res []*cleanupTarget
   416  
   417  	for i := range types.ZoneNames {
   418  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   419  		if err != nil {
   420  			return nil, err
   421  		}
   422  		zone := types.ZoneNames[i]
   423  		for j := range searched.AutoBackups {
   424  			v := searched.AutoBackups[j]
   425  			res = append(res, &cleanupTarget{
   426  				resource: v,
   427  				deleteFunc: func(ctx context.Context) error {
   428  					return op.Delete(ctx, zone, v.ID)
   429  				},
   430  			})
   431  		}
   432  	}
   433  	return res, nil
   434  }
   435  
   436  func findDatabase(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   437  	op := iaas.NewDatabaseOp(caller)
   438  	var res []*cleanupTarget
   439  
   440  	for i := range types.ZoneNames {
   441  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   442  		if err != nil {
   443  			return nil, err
   444  		}
   445  		zone := types.ZoneNames[i]
   446  		for j := range searched.Databases {
   447  			v := searched.Databases[j]
   448  			res = append(res, &cleanupTarget{
   449  				resource: v,
   450  				prepareFunc: func(ctx context.Context) error {
   451  					if err := op.Shutdown(ctx, zone, v.ID, &iaas.ShutdownOption{Force: true}); err != nil {
   452  						return err
   453  					}
   454  					_, err := iaas.WaiterForDown(func() (interface{}, error) {
   455  						return op.Read(ctx, zone, v.ID)
   456  					}).WaitForState(ctx)
   457  					return err
   458  				},
   459  				deleteFunc: func(ctx context.Context) error {
   460  					return op.Delete(ctx, zone, v.ID)
   461  				},
   462  			})
   463  		}
   464  	}
   465  	return res, nil
   466  }
   467  
   468  func findDisk(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   469  	op := iaas.NewDiskOp(caller)
   470  	var res []*cleanupTarget
   471  
   472  	for i := range types.ZoneNames {
   473  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   474  		if err != nil {
   475  			return nil, err
   476  		}
   477  		zone := types.ZoneNames[i]
   478  		for j := range searched.Disks {
   479  			v := searched.Disks[j]
   480  			res = append(res, &cleanupTarget{
   481  				resource: v,
   482  				deleteFunc: func(ctx context.Context) error {
   483  					return op.Delete(ctx, zone, v.ID)
   484  				},
   485  			})
   486  		}
   487  	}
   488  	return res, nil
   489  }
   490  
   491  func findDNS(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   492  	op := iaas.NewDNSOp(caller)
   493  	var res []*cleanupTarget
   494  
   495  	searched, err := op.Find(ctx, cleanupFindCondition)
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  	for i := range searched.DNS {
   500  		v := searched.DNS[i]
   501  		res = append(res, &cleanupTarget{
   502  			resource: v,
   503  			deleteFunc: func(ctx context.Context) error {
   504  				return op.Delete(ctx, v.ID)
   505  			},
   506  		})
   507  	}
   508  	return res, nil
   509  }
   510  
   511  func findGSLB(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   512  	op := iaas.NewGSLBOp(caller)
   513  	var res []*cleanupTarget
   514  
   515  	searched, err := op.Find(ctx, cleanupFindCondition)
   516  	if err != nil {
   517  		return nil, err
   518  	}
   519  	for i := range searched.GSLBs {
   520  		v := searched.GSLBs[i]
   521  		res = append(res, &cleanupTarget{
   522  			resource: v,
   523  			deleteFunc: func(ctx context.Context) error {
   524  				return op.Delete(ctx, v.ID)
   525  			},
   526  		})
   527  	}
   528  	return res, nil
   529  }
   530  
   531  func findIcon(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   532  	op := iaas.NewIconOp(caller)
   533  	var res []*cleanupTarget
   534  
   535  	searched, err := op.Find(ctx, cleanupFindCondition)
   536  	if err != nil {
   537  		return nil, err
   538  	}
   539  	for i := range searched.Icons {
   540  		v := searched.Icons[i]
   541  		res = append(res, &cleanupTarget{
   542  			resource: v,
   543  			deleteFunc: func(ctx context.Context) error {
   544  				return op.Delete(ctx, v.ID)
   545  			},
   546  		})
   547  	}
   548  	return res, nil
   549  }
   550  
   551  func findLicense(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   552  	op := iaas.NewLicenseOp(caller)
   553  	var res []*cleanupTarget
   554  
   555  	searched, err := op.Find(ctx, cleanupFindCondition)
   556  	if err != nil {
   557  		return nil, err
   558  	}
   559  	for i := range searched.Licenses {
   560  		v := searched.Licenses[i]
   561  		res = append(res, &cleanupTarget{
   562  			resource: v,
   563  			deleteFunc: func(ctx context.Context) error {
   564  				return op.Delete(ctx, v.ID)
   565  			},
   566  		})
   567  	}
   568  	return res, nil
   569  }
   570  
   571  func findLoadBalancer(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   572  	op := iaas.NewLoadBalancerOp(caller)
   573  	var res []*cleanupTarget
   574  
   575  	for i := range types.ZoneNames {
   576  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   577  		if err != nil {
   578  			return nil, err
   579  		}
   580  		zone := types.ZoneNames[i]
   581  		for j := range searched.LoadBalancers {
   582  			v := searched.LoadBalancers[j]
   583  			res = append(res, &cleanupTarget{
   584  				resource: v,
   585  				prepareFunc: func(ctx context.Context) error {
   586  					if err := op.Shutdown(ctx, zone, v.ID, &iaas.ShutdownOption{Force: true}); err != nil {
   587  						return err
   588  					}
   589  					_, err := iaas.WaiterForDown(func() (interface{}, error) {
   590  						return op.Read(ctx, zone, v.ID)
   591  					}).WaitForState(ctx)
   592  					return err
   593  				},
   594  				deleteFunc: func(ctx context.Context) error {
   595  					return op.Delete(ctx, zone, v.ID)
   596  				},
   597  			})
   598  		}
   599  	}
   600  	return res, nil
   601  }
   602  
   603  func findMobileGateway(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   604  	op := iaas.NewMobileGatewayOp(caller)
   605  	var res []*cleanupTarget
   606  
   607  	for i := range types.ZoneNames {
   608  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   609  		if err != nil {
   610  			return nil, err
   611  		}
   612  		zone := types.ZoneNames[i]
   613  		for j := range searched.MobileGateways {
   614  			v := searched.MobileGateways[j]
   615  			res = append(res, &cleanupTarget{
   616  				resource: v,
   617  				prepareFunc: func(ctx context.Context) error {
   618  					// delete sim routes
   619  					if err := op.SetSIMRoutes(ctx, zone, v.ID, []*iaas.MobileGatewaySIMRouteParam{}); err != nil {
   620  						return err
   621  					}
   622  
   623  					// delete SIMs
   624  					sims, err := op.ListSIM(ctx, zone, v.ID)
   625  					if err != nil {
   626  						return err
   627  					}
   628  					for _, sim := range sims {
   629  						if err := op.DeleteSIM(ctx, zone, v.ID, types.StringID(sim.ResourceID)); err != nil {
   630  							return err
   631  						}
   632  					}
   633  
   634  					if err := op.Shutdown(ctx, zone, v.ID, &iaas.ShutdownOption{Force: true}); err != nil {
   635  						return err
   636  					}
   637  					_, err = iaas.WaiterForDown(func() (interface{}, error) {
   638  						return op.Read(ctx, zone, v.ID)
   639  					}).WaitForState(ctx)
   640  					return err
   641  				},
   642  				deleteFunc: func(ctx context.Context) error {
   643  					return op.Delete(ctx, zone, v.ID)
   644  				},
   645  			})
   646  		}
   647  	}
   648  	return res, nil
   649  }
   650  
   651  func findNFS(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   652  	op := iaas.NewNFSOp(caller)
   653  	var res []*cleanupTarget
   654  
   655  	for i := range types.ZoneNames {
   656  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   657  		if err != nil {
   658  			return nil, err
   659  		}
   660  		zone := types.ZoneNames[i]
   661  		for j := range searched.NFS {
   662  			v := searched.NFS[j]
   663  			res = append(res, &cleanupTarget{
   664  				resource: v,
   665  				prepareFunc: func(ctx context.Context) error {
   666  					if err := op.Shutdown(ctx, zone, v.ID, &iaas.ShutdownOption{Force: true}); err != nil {
   667  						return err
   668  					}
   669  					_, err := iaas.WaiterForDown(func() (interface{}, error) {
   670  						return op.Read(ctx, zone, v.ID)
   671  					}).WaitForState(ctx)
   672  					return err
   673  				},
   674  				deleteFunc: func(ctx context.Context) error {
   675  					return op.Delete(ctx, zone, v.ID)
   676  				},
   677  			})
   678  		}
   679  	}
   680  	return res, nil
   681  }
   682  
   683  func findNote(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   684  	op := iaas.NewNoteOp(caller)
   685  	var res []*cleanupTarget
   686  
   687  	searched, err := op.Find(ctx, cleanupFindCondition)
   688  	if err != nil {
   689  		return nil, err
   690  	}
   691  	for i := range searched.Notes {
   692  		v := searched.Notes[i]
   693  		res = append(res, &cleanupTarget{
   694  			resource: v,
   695  			deleteFunc: func(ctx context.Context) error {
   696  				return op.Delete(ctx, v.ID)
   697  			},
   698  		})
   699  	}
   700  	return res, nil
   701  }
   702  
   703  func findPacketFilter(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   704  	op := iaas.NewPacketFilterOp(caller)
   705  	var res []*cleanupTarget
   706  
   707  	for i := range types.ZoneNames {
   708  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   709  		if err != nil {
   710  			return nil, err
   711  		}
   712  		zone := types.ZoneNames[i]
   713  		for j := range searched.PacketFilters {
   714  			v := searched.PacketFilters[j]
   715  			res = append(res, &cleanupTarget{
   716  				resource: v,
   717  				deleteFunc: func(ctx context.Context) error {
   718  					return op.Delete(ctx, zone, v.ID)
   719  				},
   720  			})
   721  		}
   722  	}
   723  	return res, nil
   724  }
   725  
   726  func findProxyLB(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   727  	op := iaas.NewProxyLBOp(caller)
   728  	var res []*cleanupTarget
   729  
   730  	searched, err := op.Find(ctx, cleanupFindCondition)
   731  	if err != nil {
   732  		return nil, err
   733  	}
   734  	for i := range searched.ProxyLBs {
   735  		v := searched.ProxyLBs[i]
   736  		res = append(res, &cleanupTarget{
   737  			resource: v,
   738  			deleteFunc: func(ctx context.Context) error {
   739  				return op.Delete(ctx, v.ID)
   740  			},
   741  		})
   742  	}
   743  	return res, nil
   744  }
   745  
   746  func findServer(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   747  	op := iaas.NewServerOp(caller)
   748  	var res []*cleanupTarget
   749  
   750  	for i := range types.ZoneNames {
   751  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   752  		if err != nil {
   753  			return nil, err
   754  		}
   755  		zone := types.ZoneNames[i]
   756  		for j := range searched.Servers {
   757  			v := searched.Servers[j]
   758  			res = append(res, &cleanupTarget{
   759  				resource: v,
   760  				prepareFunc: func(ctx context.Context) error {
   761  					if err := op.Shutdown(ctx, zone, v.ID, &iaas.ShutdownOption{Force: true}); err != nil {
   762  						return err
   763  					}
   764  					_, err := iaas.WaiterForDown(func() (interface{}, error) {
   765  						return op.Read(ctx, zone, v.ID)
   766  					}).WaitForState(ctx)
   767  					return err
   768  				},
   769  				deleteFunc: func(ctx context.Context) error {
   770  					return op.Delete(ctx, zone, v.ID)
   771  				},
   772  			})
   773  		}
   774  	}
   775  	return res, nil
   776  }
   777  
   778  func findSIM(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   779  	op := iaas.NewSIMOp(caller)
   780  	var res []*cleanupTarget
   781  
   782  	searched, err := op.Find(ctx, cleanupFindCondition)
   783  	if err != nil {
   784  		return nil, err
   785  	}
   786  	for i := range searched.SIMs {
   787  		v := searched.SIMs[i]
   788  		res = append(res, &cleanupTarget{
   789  			resource: v,
   790  			deleteFunc: func(ctx context.Context) error {
   791  				return op.Delete(ctx, v.ID)
   792  			},
   793  		})
   794  	}
   795  	return res, nil
   796  }
   797  
   798  func findSimpleMonitor(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   799  	op := iaas.NewSimpleMonitorOp(caller)
   800  	var res []*cleanupTarget
   801  
   802  	searched, err := op.Find(ctx, cleanupFindCondition)
   803  	if err != nil {
   804  		return nil, err
   805  	}
   806  	for i := range searched.SimpleMonitors {
   807  		v := searched.SimpleMonitors[i]
   808  		res = append(res, &cleanupTarget{
   809  			resource: v,
   810  			deleteFunc: func(ctx context.Context) error {
   811  				return op.Delete(ctx, v.ID)
   812  			},
   813  		})
   814  	}
   815  	return res, nil
   816  }
   817  
   818  func findSSHKey(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   819  	op := iaas.NewSSHKeyOp(caller)
   820  	var res []*cleanupTarget
   821  
   822  	searched, err := op.Find(ctx, cleanupFindCondition)
   823  	if err != nil {
   824  		return nil, err
   825  	}
   826  	for i := range searched.SSHKeys {
   827  		v := searched.SSHKeys[i]
   828  		res = append(res, &cleanupTarget{
   829  			resource: v,
   830  			deleteFunc: func(ctx context.Context) error {
   831  				return op.Delete(ctx, v.ID)
   832  			},
   833  		})
   834  	}
   835  	return res, nil
   836  }
   837  
   838  func findVPCRouter(ctx context.Context, caller iaas.APICaller) ([]*cleanupTarget, error) {
   839  	op := iaas.NewVPCRouterOp(caller)
   840  	var res []*cleanupTarget
   841  
   842  	for i := range types.ZoneNames {
   843  		searched, err := op.Find(ctx, types.ZoneNames[i], cleanupFindCondition)
   844  		if err != nil {
   845  			return nil, err
   846  		}
   847  		zone := types.ZoneNames[i]
   848  		for j := range searched.VPCRouters {
   849  			v := searched.VPCRouters[j]
   850  			res = append(res, &cleanupTarget{
   851  				resource: v,
   852  				prepareFunc: func(ctx context.Context) error {
   853  					if err := op.Shutdown(ctx, zone, v.ID, &iaas.ShutdownOption{Force: true}); err != nil {
   854  						return err
   855  					}
   856  					_, err := iaas.WaiterForDown(func() (interface{}, error) {
   857  						return op.Read(ctx, zone, v.ID)
   858  					}).WaitForState(ctx)
   859  					return err
   860  				},
   861  				deleteFunc: func(ctx context.Context) error {
   862  					return op.Delete(ctx, zone, v.ID)
   863  				},
   864  			})
   865  		}
   866  	}
   867  	return res, nil
   868  }