(ctx context.Context, project *composetypes.Project)
| 337 | } |
| 338 | |
| 339 | func (d *Deployer) createVolumes(ctx context.Context, project *composetypes.Project) error { |
| 340 | // Project-filtered listing keeps the response small on hosts with many stacks. |
| 341 | ownedList, err := d.cli.VolumeList(ctx, client.VolumeListOptions{ |
| 342 | Filters: make(client.Filters).Add("label", labelComposeProject+"="+project.Name), |
| 343 | }) |
| 344 | if err != nil { |
| 345 | return fmt.Errorf("listing volumes: %w", err) |
| 346 | } |
| 347 | ownedByName := make(map[string]struct{}, len(ownedList.Items)) |
| 348 | for _, v := range ownedList.Items { |
| 349 | ownedByName[v.Name] = struct{}{} |
| 350 | } |
| 351 | |
| 352 | // External volumes are looked up unfiltered, on demand (they are not project-labeled). |
| 353 | var externalByName map[string]struct{} |
| 354 | lookupExternal := func() error { |
| 355 | if externalByName != nil { |
| 356 | return nil |
| 357 | } |
| 358 | all, err := d.cli.VolumeList(ctx, client.VolumeListOptions{}) |
| 359 | if err != nil { |
| 360 | return fmt.Errorf("listing external volumes: %w", err) |
| 361 | } |
| 362 | externalByName = make(map[string]struct{}, len(all.Items)) |
| 363 | for _, v := range all.Items { |
| 364 | externalByName[v.Name] = struct{}{} |
| 365 | } |
| 366 | return nil |
| 367 | } |
| 368 | |
| 369 | for name, volCfg := range project.Volumes { |
| 370 | if bool(volCfg.External) { |
| 371 | extName := volCfg.Name |
| 372 | if extName == "" { |
| 373 | extName = name |
| 374 | } |
| 375 | if err := lookupExternal(); err != nil { |
| 376 | return err |
| 377 | } |
| 378 | if _, ok := externalByName[extName]; !ok { |
| 379 | return fmt.Errorf("external volume %q not found", extName) |
| 380 | } |
| 381 | continue |
| 382 | } |
| 383 | |
| 384 | fullName := volCfg.Name |
| 385 | if fullName == "" { |
| 386 | fullName = project.Name + "_" + name |
| 387 | } |
| 388 | |
| 389 | if _, ok := ownedByName[fullName]; ok { |
| 390 | log.Info().Str("volume", fullName).Msg("Volume already exists, skipping") |
| 391 | continue |
| 392 | } |
| 393 | |
| 394 | driver := volCfg.Driver |
| 395 | if driver == "" { |
| 396 | driver = "local" |
no test coverage detected