Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

consolidate create node container #447

Merged
merged 9 commits into from
Mar 24, 2023
2 changes: 1 addition & 1 deletion chain/cosmos/broadcaster.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (b *Broadcaster) GetClientContext(ctx context.Context, user User) (client.C
if !ok {
localDir := b.t.TempDir()
containerKeyringDir := path.Join(cn.HomeDir(), "keyring-test")
kr, err := dockerutil.NewLocalKeyringFromDockerContainer(ctx, cn.DockerClient, localDir, containerKeyringDir, cn.containerID)
kr, err := dockerutil.NewLocalKeyringFromDockerContainer(ctx, cn.DockerClient, localDir, containerKeyringDir, cn.containerLifecycle.ContainerID())
if err != nil {
return client.Context{}, err
}
Expand Down
108 changes: 31 additions & 77 deletions chain/cosmos/chain_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ import (
"github.com/cosmos/cosmos-sdk/types"
paramsutils "github.com/cosmos/cosmos-sdk/x/params/client/utils"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
dockertypes "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
dockerclient "github.com/docker/docker/client"
"github.com/docker/docker/errdefs"
"github.com/docker/go-connections/nat"
"github.com/strangelove-ventures/interchaintest/v7/ibc"
"github.com/strangelove-ventures/interchaintest/v7/internal/blockdb"
Expand All @@ -57,7 +53,7 @@ type ChainNode struct {
lock sync.Mutex
log *zap.Logger

containerID string
containerLifecycle *dockerutil.ContainerLifecycle

// Ports set during StartContainer.
hostRPCPort string
Expand All @@ -66,6 +62,25 @@ type ChainNode struct {
preStartListeners dockerutil.Listeners
}

func NewChainNode(log *zap.Logger, validator bool, chain *CosmosChain, dockerClient *dockerclient.Client, networkID string, testName string, image ibc.DockerImage, index int) *ChainNode {
tn := &ChainNode{
log: log,

Validator: validator,

Chain: chain,
DockerClient: dockerClient,
NetworkID: networkID,
TestName: testName,
Image: image,
Index: index,
}

tn.containerLifecycle = dockerutil.NewContainerLifecycle(log, dockerClient, tn.Name())

return tn
}

// ChainNodes is a collection of ChainNode
type ChainNodes []*ChainNode

Expand Down Expand Up @@ -925,81 +940,28 @@ func (tn *ChainNode) UnsafeResetAll(ctx context.Context) error {

func (tn *ChainNode) CreateNodeContainer(ctx context.Context) error {
chainCfg := tn.Chain.Config()
cmd := []string{chainCfg.Bin, "start", "--home", tn.HomeDir(), "--x-crisis-skip-assert-invariants"}

var cmd []string
if chainCfg.NoHostMount {
cmd = []string{"sh", "-c", fmt.Sprintf("cp -r %s %s_nomnt && %s start --home %s_nomnt --x-crisis-skip-assert-invariants", tn.HomeDir(), tn.HomeDir(), chainCfg.Bin, tn.HomeDir())}
} else {
cmd = []string{chainCfg.Bin, "start", "--home", tn.HomeDir(), "--x-crisis-skip-assert-invariants"}
}
imageRef := tn.Image.Ref()
tn.logger().
Info("Running command",
zap.String("command", strings.Join(cmd, " ")),
zap.String("container", tn.Name()),
zap.String("image", imageRef),
)

pb, listeners, err := dockerutil.GeneratePortBindings(sentryPorts)
if err != nil {
return fmt.Errorf("failed to generate port bindings: %w", err)
}

tn.preStartListeners = listeners

cc, err := tn.DockerClient.ContainerCreate(
ctx,
&container.Config{
Image: imageRef,

Entrypoint: []string{},
Cmd: cmd,

Hostname: tn.HostName(),

Labels: map[string]string{dockerutil.CleanupLabel: tn.TestName},

ExposedPorts: sentryPorts,
},
&container.HostConfig{
Binds: tn.Bind(),
PortBindings: pb,
PublishAllPorts: true,
AutoRemove: false,
DNS: []string{},
},
&network.NetworkingConfig{
EndpointsConfig: map[string]*network.EndpointSettings{
tn.NetworkID: {},
},
},
nil,
tn.Name(),
)
if err != nil {
tn.preStartListeners.CloseAll()
return err
}
tn.containerID = cc.ID
return nil
return tn.containerLifecycle.CreateContainer(ctx, tn.TestName, tn.NetworkID, tn.Image, sentryPorts, tn.Bind(), tn.HostName(), cmd)
}

func (tn *ChainNode) StartContainer(ctx context.Context) error {
dockerutil.LockPortAssignment()
tn.preStartListeners.CloseAll()
err := dockerutil.StartContainer(ctx, tn.DockerClient, tn.containerID)
dockerutil.UnlockPortAssignment()
if err != nil {
if err := tn.containerLifecycle.StartContainer(ctx); err != nil {
return err
}

c, err := tn.DockerClient.ContainerInspect(ctx, tn.containerID)
// Set the host ports once since they will not change after the container has started.
hostPorts, err := tn.containerLifecycle.GetHostPorts(ctx, rpcPort, grpcPort)
if err != nil {
return err
}

// Set the host ports once since they will not change after the container has started.
tn.hostRPCPort = dockerutil.GetHostPort(c, rpcPort)
tn.hostGRPCPort = dockerutil.GetHostPort(c, grpcPort)

tn.logger().Info("Cosmos chain node started", zap.String("container", tn.Name()), zap.String("rpc_port", tn.hostRPCPort))
tn.hostRPCPort, tn.hostGRPCPort = hostPorts[0], hostPorts[1]

err = tn.NewClient("tcp://" + tn.hostRPCPort)
if err != nil {
Expand All @@ -1022,19 +984,11 @@ func (tn *ChainNode) StartContainer(ctx context.Context) error {
}

func (tn *ChainNode) StopContainer(ctx context.Context) error {
timeout := 30 * time.Second
return tn.DockerClient.ContainerStop(ctx, tn.containerID, &timeout)
return tn.containerLifecycle.StopContainer(ctx)
}

func (tn *ChainNode) RemoveContainer(ctx context.Context) error {
err := tn.DockerClient.ContainerRemove(ctx, tn.containerID, dockertypes.ContainerRemoveOptions{
Force: true,
RemoveVolumes: true,
})
if err != nil && !errdefs.IsNotFound(err) {
return fmt.Errorf("remove container %s: %w", tn.Name(), err)
}
return nil
return tn.containerLifecycle.RemoveContainer(ctx)
}

// InitValidatorFiles creates the node files and signs a genesis transaction
Expand Down
19 changes: 4 additions & 15 deletions chain/cosmos/cosmos_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,20 +547,11 @@ func (c *CosmosChain) NewChainNode(
networkID string,
image ibc.DockerImage,
validator bool,
index int,
) (*ChainNode, error) {
// Construct the ChainNode first so we can access its name.
// The ChainNode's VolumeName cannot be set until after we create the volume.
tn := &ChainNode{
log: c.log,

Validator: validator,

Chain: c,
DockerClient: cli,
NetworkID: networkID,
TestName: testName,
Image: image,
}
tn := NewChainNode(c.log, validator, c, cli, networkID, testName, image, index)

v, err := cli.VolumeCreate(ctx, volumetypes.VolumeCreateBody{
Labels: map[string]string{
Expand Down Expand Up @@ -609,23 +600,21 @@ func (c *CosmosChain) initializeChainNodes(
for i := len(c.Validators); i < c.numValidators; i++ {
i := i
eg.Go(func() error {
val, err := c.NewChainNode(egCtx, testName, cli, networkID, image, true)
val, err := c.NewChainNode(egCtx, testName, cli, networkID, image, true, i)
if err != nil {
return err
}
val.Index = i
newVals[i] = val
return nil
})
}
for i := len(c.FullNodes); i < c.numFullNodes; i++ {
i := i
eg.Go(func() error {
fn, err := c.NewChainNode(egCtx, testName, cli, networkID, image, false)
fn, err := c.NewChainNode(egCtx, testName, cli, networkID, image, false, i)
if err != nil {
return err
}
fn.Index = i
newFullNodes[i] = fn
return nil
})
Expand Down
74 changes: 15 additions & 59 deletions chain/internal/tendermint/tendermint_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import (
rpcclient "github.com/cometbft/cometbft/rpc/client"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
libclient "github.com/cometbft/cometbft/rpc/jsonrpc/client"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
dockerclient "github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"github.com/hashicorp/go-version"
Expand All @@ -38,9 +36,16 @@ type TendermintNode struct {
TestName string
Image ibc.DockerImage

containerID string
containerLifecycle *dockerutil.ContainerLifecycle
}

func NewTendermintNode(log *zap.Logger, i int, c ibc.Chain, dockerClient *dockerclient.Client, networkID string, testName string, image ibc.DockerImage) *TendermintNode {
tn := &TendermintNode{Log: log, Index: i, Chain: c,
DockerClient: dockerClient, NetworkID: networkID, TestName: testName, Image: image}

preStartListeners dockerutil.Listeners
tn.containerLifecycle = dockerutil.NewContainerLifecycle(log, dockerClient, tn.Name())

return tn
}

// TendermintNodes is a collection of TendermintNode
Expand Down Expand Up @@ -220,75 +225,26 @@ func (tn *TendermintNode) CreateNodeContainer(ctx context.Context, additionalFla
chainCfg := tn.Chain.Config()
cmd := []string{chainCfg.Bin, "start", "--home", tn.HomeDir()}
cmd = append(cmd, additionalFlags...)
fmt.Printf("{%s} -> '%s'\n", tn.Name(), strings.Join(cmd, " "))

pb, listeners, err := dockerutil.GeneratePortBindings(sentryPorts)
if err != nil {
return fmt.Errorf("failed to generate port bindings: %w", err)
}

tn.preStartListeners = listeners

cc, err := tn.DockerClient.ContainerCreate(
ctx,
&container.Config{
Image: tn.Image.Ref(),

Entrypoint: []string{},
Cmd: cmd,

Hostname: tn.HostName(),

Labels: map[string]string{dockerutil.CleanupLabel: tn.TestName},

ExposedPorts: sentryPorts,
},
&container.HostConfig{
Binds: tn.Bind(),
PortBindings: pb,
PublishAllPorts: true,
AutoRemove: false,
DNS: []string{},
},
&network.NetworkingConfig{
EndpointsConfig: map[string]*network.EndpointSettings{
tn.NetworkID: {},
},
},
nil,
tn.Name(),
)
if err != nil {
tn.preStartListeners.CloseAll()
return err
}
tn.containerID = cc.ID
return nil
return tn.containerLifecycle.CreateContainer(ctx, tn.TestName, tn.NetworkID, tn.Image, sentryPorts, tn.Bind(), tn.HostName(), cmd)
}

func (tn *TendermintNode) StopContainer(ctx context.Context) error {
timeout := 30 * time.Second
return tn.DockerClient.ContainerStop(ctx, tn.containerID, &timeout)
return tn.containerLifecycle.StopContainer(ctx)
}

func (tn *TendermintNode) StartContainer(ctx context.Context) error {
dockerutil.LockPortAssignment()
tn.preStartListeners.CloseAll()
err := dockerutil.StartContainer(ctx, tn.DockerClient, tn.containerID)
dockerutil.UnlockPortAssignment()
if err != nil {
if err := tn.containerLifecycle.StartContainer(ctx); err != nil {
return err
}

c, err := tn.DockerClient.ContainerInspect(ctx, tn.containerID)
hostPorts, err := tn.containerLifecycle.GetHostPorts(ctx, rpcPort)
if err != nil {
return err
}
rpcPort := hostPorts[0]

port := dockerutil.GetHostPort(c, rpcPort)
fmt.Printf("{%s} RPC => %s\n", tn.Name(), port)

err = tn.NewClient(fmt.Sprintf("tcp://%s", port))
err = tn.NewClient(fmt.Sprintf("tcp://%s", rpcPort))
if err != nil {
return err
}
Expand Down
Loading