diff --git a/core/commands/swarm.go b/core/commands/swarm.go index 252c48d334e..c0ff131d1f3 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -71,6 +71,7 @@ const ( swarmLatencyOptionName = "latency" swarmDirectionOptionName = "direction" swarmResetLimitsOptionName = "reset" + swarmSaveOptionName = "save" swarmUsedResourcesPercentageName = "min-used-limit-perc" swarmIdentifyOptionName = "identify" ) @@ -107,6 +108,9 @@ var swarmPeeringAddCmd = &cmds.Command{ Arguments: []cmds.Argument{ cmds.StringArg("address", true, true, "address of peer to add into the peering subsystem"), }, + Options: []cmds.Option{ + cmds.BoolOption(swarmSaveOptionName, "if set, address(es) will be saved to peering config"), + }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { addrs := make([]ma.Multiaddr, len(req.Arguments)) @@ -139,6 +143,18 @@ var swarmPeeringAddCmd = &cmds.Command{ return err } } + + save, _ := req.Options[swarmSaveOptionName].(bool) + if save { + update := func(cfg *config.Config) { + cfg.Peering.Peers = append(cfg.Peering.Peers, addInfos...) + } + err := updateAndPersistConfig(env, update) + if err != nil { + return fmt.Errorf("unable to update and persist config change: %w", err) + } + } + return nil }, Encoders: cmds.EncoderMap{ @@ -197,6 +213,9 @@ var swarmPeeringRmCmd = &cmds.Command{ Arguments: []cmds.Argument{ cmds.StringArg("ID", true, true, "ID of peer to remove from the peering subsystem"), }, + Options: []cmds.Option{ + cmds.BoolOption(swarmSaveOptionName, "if set, address(es) will be removed from peering config"), + }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { node, err := cmdenv.GetNode(env) if err != nil { @@ -206,17 +225,40 @@ var swarmPeeringRmCmd = &cmds.Command{ return ErrNotOnline } + pids := make(map[peer.ID]struct{}, len(req.Arguments)) for _, arg := range req.Arguments { id, err := peer.Decode(arg) if err != nil { return err } - + pids[id] = struct{}{} node.Peering.RemovePeer(id) if err = res.Emit(peeringResult{id, "success"}); err != nil { return err } } + + save, _ := req.Options[swarmSaveOptionName].(bool) + if save { + update := func(cfg *config.Config) { + var cfgOut []peer.AddrInfo + for _, p := range cfg.Peering.Peers { + if _, ok := pids[p.ID]; ok { + continue + } + + cfgOut = append(cfgOut, p) + } + + cfg.Peering.Peers = cfgOut + } + + err := updateAndPersistConfig(env, update) + if err != nil { + return fmt.Errorf("unable to update and persist config change: %w", err) + } + } + return nil }, Type: peeringResult{}, @@ -1081,3 +1123,20 @@ func filtersRemove(r repo.Repo, cfg *config.Config, toRemoveFilters []string) ([ return removed, nil } + +func updateAndPersistConfig(env cmds.Environment, update func(*config.Config)) error { + r, err := fsrepo.Open(env.(*commands.Context).ConfigRoot) + if err != nil { + return fmt.Errorf("error opening repo: %w", err) + } + defer r.Close() + cfg, err := r.Config() + if err != nil { + return fmt.Errorf("error fetching config file: %w", err) + } + update(cfg) + if err := r.SetConfig(cfg); err != nil { + return fmt.Errorf("error setting config: %w", err) + } + return nil +} diff --git a/test/sharness/t0140-swarm.sh b/test/sharness/t0140-swarm.sh index d65831d3e22..2851bb9ac08 100755 --- a/test/sharness/t0140-swarm.sh +++ b/test/sharness/t0140-swarm.sh @@ -160,6 +160,35 @@ test_expect_success 'peering is removed' ' test_kill_ipfs_daemon +test_launch_ipfs_daemon + +peeringID='QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5N' +peeringID2='QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5K' +peeringAddr='/ip4/1.2.3.4/tcp/1234/p2p/QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5N' +peeringAddr2='/ip4/1.2.3.4/tcp/1234/p2p/QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5K' + +test_expect_success "'ipfs swarm peering add' with save option mutates config" ' + ipfs config Peering.Peers > start-peers && + ipfs swarm peering add ${peeringAddr} ${peeringAddr2} --save && + ipfs config Peering.Peers > end-peers && + ! test_cmp start-peers end-peers && + test_should_contain "${peeringID}" end-peers && + test_should_contain ${peeringID2} end-peers && + rm start-peers end-peers +' + +test_expect_success "'ipfs swarm peering rm' with save option mutates config" ' + ipfs config Peering.Peers > start-peers && + ipfs swarm peering rm ${peeringID} --save && + ipfs config Peering.Peers > end-peers && + ! test_cmp start-peers end-peers && + test_should_not_contain "${peeringID}" end-peers && + test_should_contain ${peeringID2} end-peers && + rm start-peers end-peers +' + +test_kill_ipfs_daemon + test_expect_success "set up tcp testbed" ' iptb testbed create -type localipfs -count 2 -force -init '