diff --git a/internal/constants/constants.go b/internal/constants/constants.go index ac2d7bbf..21f47066 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -23,7 +23,7 @@ import ( var StacksDir = checkHome() var FireFlyCoreImageName = "ghcr.io/hyperledger-firefly/firefly" -var IPFSImageName = "ipfs/go-ipfs:v0.10.0" +var IPFSImageName = "ipfs/kubo:v0.42.0" var PostgresImageName = "postgres" var PrometheusImageName = "prom/prometheus" var SandboxImageName = "ghcr.io/hyperledger-firefly/sandbox:latest" diff --git a/internal/docker/docker_config.go b/internal/docker/docker_config.go index 97088d5a..383c4d17 100644 --- a/internal/docker/docker_config.go +++ b/internal/docker/docker_config.go @@ -167,6 +167,11 @@ func CreateDockerCompose(s *types.Stack) *DockerComposeConfig { "LIBP2P_FORCE_PNET": "1", }, ) + // Kubo's AutoConf/public-network defaults are incompatible with a + // private swarm and prevent peering with other members unless + // disabled via a container-init.d script - see ipfs_config.go. + sharedStorage.Volumes = append(sharedStorage.Volumes, fmt.Sprintf("ipfs_init_%s:/container-init.d", member.ID)) + compose.Volumes[fmt.Sprintf("ipfs_init_%s", member.ID)] = struct{}{} } else { sharedStorage.Environment = s.EnvironmentVars } diff --git a/internal/stacks/ipfs_config.go b/internal/stacks/ipfs_config.go index a63f006c..e05f8541 100644 --- a/internal/stacks/ipfs_config.go +++ b/internal/stacks/ipfs_config.go @@ -29,3 +29,20 @@ func GenerateSwarmKey() (string, error) { hexKey := hex.EncodeToString(key) return "/key/swarm/psk/1.0.0/\n/base16/\n" + hexKey, nil } + +// GenerateIPFSPrivateNetInitScript returns a container-init.d script that +// disables Kubo's AutoConf/public-network defaults, which are incompatible +// with a private swarm (swarm.key / LIBP2P_FORCE_PNET) and otherwise prevent +// the daemon from starting or from ever peering with other members. +func GenerateIPFSPrivateNetInitScript() string { + return `#!/bin/sh +ipfs config --json AutoConf.Enabled false +ipfs config --json Bootstrap '[]' +ipfs config --json DNS.Resolvers '{}' +ipfs config --json Routing.DelegatedRouters '[]' +ipfs config --json Ipns.DelegatedPublishers '[]' +ipfs config Routing.Type dht +ipfs config --json AutoTLS.Enabled false +ipfs config --json Swarm.Transports.Network.Websocket false +` +} diff --git a/internal/stacks/stack_manager.go b/internal/stacks/stack_manager.go index c8bfb7f6..e014b876 100644 --- a/internal/stacks/stack_manager.go +++ b/internal/stacks/stack_manager.go @@ -505,6 +505,13 @@ func (s *StackManager) writeConfig(options *types.InitOptions) error { } } + if s.Stack.IPFSMode.Equals(types.IPFSModePrivate) { + initScript := GenerateIPFSPrivateNetInitScript() + if err := os.WriteFile(path.Join(s.Stack.InitDir, "config", "ipfs_privatenet_init.sh"), []byte(initScript), 0755); err != nil { + return err + } + } + return nil } @@ -566,6 +573,21 @@ func (s *StackManager) copyDataExchangeConfigToVolumes() error { return nil } +func (s *StackManager) copyIPFSInitScriptToVolumes() error { + if !s.Stack.IPFSMode.Equals(types.IPFSModePrivate) { + return nil + } + configDir := filepath.Join(s.Stack.RuntimeDir, "config") + scriptPath := path.Join(configDir, "ipfs_privatenet_init.sh") + for _, member := range s.Stack.Members { + volumeName := fmt.Sprintf("%s_ipfs_init_%s", s.Stack.Name, member.ID) + if err := docker.CopyFileToVolume(s.ctx, volumeName, scriptPath, "/privatenet-init.sh"); err != nil { + return err + } + } + return nil +} + func (s *StackManager) createMember(id string, index int, options *types.InitOptions, external bool) (*types.Organization, error) { serviceBase := options.ServicesBasePort + (index * 100) ptmBase := options.PtmBasePort + (index * 10) @@ -908,6 +930,10 @@ func (s *StackManager) runFirstTimeSetup(options *types.StartOptions) (messages return messages, err } + if err := s.copyIPFSInitScriptToVolumes(); err != nil { + return messages, err + } + pullOptions := &types.PullOptions{ Retries: 2, }