| 1 | // package mg17 contains the code to perform 17-18 repository migration in Kubo. |
| 2 | // This handles the following: |
| 3 | // - Migrate Provider and Reprovider configs to unified Provide config |
| 4 | // - Clear deprecated Provider and Reprovider fields |
| 5 | // - Increment repo version to 18 |
| 6 | package mg17 |
| 7 | |
| 8 | import ( |
| 9 | "fmt" |
| 10 | "io" |
| 11 | |
| 12 | "github.com/ipfs/kubo/repo/fsrepo/migrations/common" |
| 13 | ) |
| 14 | |
| 15 | // Migration is the main exported migration for 17-to-18 |
| 16 | var Migration = &common.BaseMigration{ |
| 17 | FromVersion: "17", |
| 18 | ToVersion: "18", |
| 19 | Description: "Migrating Provider and Reprovider configuration to unified Provide configuration", |
| 20 | Convert: convert, |
| 21 | } |
| 22 | |
| 23 | // NewMigration creates a new migration instance (for compatibility) |
| 24 | func NewMigration() common.Migration { |
| 25 | return Migration |
| 26 | } |
| 27 | |
| 28 | // convert performs the actual configuration transformation |
| 29 | func convert(in io.ReadSeeker, out io.Writer) error { |
| 30 | // Read the configuration |
| 31 | confMap, err := common.ReadConfig(in) |
| 32 | if err != nil { |
| 33 | return err |
| 34 | } |
| 35 | |
| 36 | // Create new Provide section with DHT subsection from Provider and Reprovider |
| 37 | provide := make(map[string]any) |
| 38 | dht := make(map[string]any) |
| 39 | hasNonDefaultValues := false |
| 40 | |
| 41 | // Migrate Provider fields if they exist |
| 42 | provider := common.SafeCastMap(confMap["Provider"]) |
| 43 | if enabled, exists := provider["Enabled"]; exists { |
| 44 | provide["Enabled"] = enabled |
| 45 | // Log migration for non-default values |
| 46 | if enabledBool, ok := enabled.(bool); ok && !enabledBool { |
| 47 | fmt.Printf(" Migrated Provider.Enabled=%v to Provide.Enabled=%v\n", enabledBool, enabledBool) |
| 48 | hasNonDefaultValues = true |
| 49 | } |
| 50 | } |
| 51 | if workerCount, exists := provider["WorkerCount"]; exists { |
| 52 | dht["MaxWorkers"] = workerCount |
| 53 | // Log migration for all worker count values |
| 54 | if count, ok := workerCount.(float64); ok { |
| 55 | fmt.Printf(" Migrated Provider.WorkerCount=%v to Provide.DHT.MaxWorkers=%v\n", int(count), int(count)) |
| 56 | hasNonDefaultValues = true |
| 57 | |
| 58 | // Additional guidance for high WorkerCount |
| 59 | if count > 5 { |
| 60 | fmt.Printf(" ⚠️ For better resource utilization, consider enabling Provide.DHT.SweepEnabled=true\n") |
| 61 | fmt.Printf(" and adjusting Provide.DHT.DedicatedBurstWorkers if announcement of new CIDs\n") |
| 62 | fmt.Printf(" should take priority over periodic reprovide interval.\n") |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | // Note: Skip Provider.Strategy as it was unused |
| 67 | |
| 68 | // Migrate Reprovider fields if they exist |
| 69 | reprovider := common.SafeCastMap(confMap["Reprovider"]) |
| 70 | if strategy, exists := reprovider["Strategy"]; exists { |
| 71 | if strategyStr, ok := strategy.(string); ok { |
| 72 | // Convert deprecated "flat" strategy to "all" |
| 73 | if strategyStr == "flat" { |
| 74 | provide["Strategy"] = "all" |
| 75 | fmt.Printf(" Migrated deprecated Reprovider.Strategy=\"flat\" to Provide.Strategy=\"all\"\n") |
| 76 | } else { |
| 77 | // Migrate any other strategy value as-is |
| 78 | provide["Strategy"] = strategyStr |
| 79 | fmt.Printf(" Migrated Reprovider.Strategy=\"%s\" to Provide.Strategy=\"%s\"\n", strategyStr, strategyStr) |
| 80 | } |
| 81 | hasNonDefaultValues = true |
| 82 | } else { |
| 83 | // Not a string, set to default "all" to ensure valid config |
| 84 | provide["Strategy"] = "all" |
| 85 | fmt.Printf(" Warning: Reprovider.Strategy was not a string, setting Provide.Strategy=\"all\"\n") |
| 86 | hasNonDefaultValues = true |
| 87 | } |
| 88 | } |
| 89 | if interval, exists := reprovider["Interval"]; exists { |
| 90 | dht["Interval"] = interval |
| 91 | // Log migration for non-default intervals |
| 92 | if intervalStr, ok := interval.(string); ok && intervalStr != "22h" && intervalStr != "" { |
| 93 | fmt.Printf(" Migrated Reprovider.Interval=\"%s\" to Provide.DHT.Interval=\"%s\"\n", intervalStr, intervalStr) |
| 94 | hasNonDefaultValues = true |
| 95 | } |
| 96 | } |
| 97 | // Note: Sweep is a new field introduced in v0.38, not present in v0.37 |
| 98 | // So we don't need to migrate it from Reprovider |
| 99 | |
| 100 | // Set the DHT section if we have any DHT fields to migrate |
| 101 | if len(dht) > 0 { |
| 102 | provide["DHT"] = dht |
| 103 | } |
| 104 | |
| 105 | // Set the new Provide section if we have any fields to migrate |
| 106 | if len(provide) > 0 { |
| 107 | confMap["Provide"] = provide |
| 108 | } |
| 109 | |
| 110 | // Clear old Provider and Reprovider sections |
| 111 | delete(confMap, "Provider") |
| 112 | delete(confMap, "Reprovider") |
| 113 | |
| 114 | // Print documentation link if we migrated any non-default values |
| 115 | if hasNonDefaultValues { |
| 116 | fmt.Printf(" See: https://github.com/ipfs/kubo/blob/master/docs/config.md#provide\n") |
| 117 | } |
| 118 | |
| 119 | // Write the updated config |
| 120 | return common.WriteConfig(out, confMap) |
| 121 | } |