-
Jonas Theis authored
* Use sync beacon follower plugin instead of sync plugin * Remove sync and bootstrap plugin * Refactor sync beacon stuff * Update Docker network to use sync beacon plugins *
Add detailed sync status to dashboard * Add detailed sync status to info API * Fix linter warning * Add Explorer support for sync beacon messages * Initial integration test support for sync beacon plugins * Fix consensus integration test * Disable sync beacon follower plugin according to config * Fix dRNG integration-test * Fix sync beacon test * Fix common integration test * Clean up and add some comments Co-authored-by:capossele <angelocapossele@gmail.com>
Jonas Theis authored* Use sync beacon follower plugin instead of sync plugin * Remove sync and bootstrap plugin * Refactor sync beacon stuff * Update Docker network to use sync beacon plugins *
Add detailed sync status to dashboard * Add detailed sync status to info API * Fix linter warning * Add Explorer support for sync beacon messages * Initial integration test support for sync beacon plugins * Fix consensus integration test * Disable sync beacon follower plugin according to config * Fix dRNG integration-test * Fix sync beacon test * Fix common integration test * Clean up and add some comments Co-authored-by:capossele <angelocapossele@gmail.com>
docker.go 8.28 KiB
package framework
import (
"context"
"fmt"
"io"
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
)
// newDockerClient creates a Docker client that communicates via the Docker socket.
func newDockerClient() (*client.Client, error) {
return client.NewClient(
"unix:///var/run/docker.sock",
"",
nil,
nil,
)
}
// DockerContainer is a wrapper object for a Docker container.
type DockerContainer struct {
client *client.Client
id string
}
// NewDockerContainer creates a new DockerContainer.
func NewDockerContainer(c *client.Client) *DockerContainer {
return &DockerContainer{client: c}
}
// NewDockerContainerFromExisting creates a new DockerContainer from an already existing Docker container by name.
func NewDockerContainerFromExisting(c *client.Client, name string) (*DockerContainer, error) {
containers, err := c.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
return nil, err
}
for _, cont := range containers {
if cont.Names[0] == name {
return &DockerContainer{
client: c,
id: cont.ID,
}, nil
}
}
return nil, fmt.Errorf("could not find container with name '%s'", name)
}
// CreateGoShimmerEntryNode creates a new container with the GoShimmer entry node's configuration.
func (d *DockerContainer) CreateGoShimmerEntryNode(name string, seed string) error {
containerConfig := &container.Config{
Image: "iotaledger/goshimmer",
ExposedPorts: nil,
Cmd: strslice.StrSlice{
"--skip-config=true",
"--logger.level=debug",
fmt.Sprintf("--node.disablePlugins=%s", disabledPluginsEntryNode),
"--autopeering.entryNodes=",
fmt.Sprintf("--autopeering.seed=base58:%s", seed),
},
}
return d.CreateContainer(name, containerConfig)
}
// CreateGoShimmerPeer creates a new container with the GoShimmer peer's configuration.
func (d *DockerContainer) CreateGoShimmerPeer(config GoShimmerConfig) error {
// configure GoShimmer container instance
containerConfig := &container.Config{
Image: "iotaledger/goshimmer",
ExposedPorts: nat.PortSet{
nat.Port("8080/tcp"): {},
},
Cmd: strslice.StrSlice{
"--skip-config=true",
"--logger.level=debug",
fmt.Sprintf("--valueLayer.fcob.averageNetworkDelay=%d", ParaFCoBAverageNetworkDelay),
fmt.Sprintf("--node.disablePlugins=%s", config.DisabledPlugins),
fmt.Sprintf("--pow.difficulty=%d", ParaPoWDifficulty),
fmt.Sprintf("--faucet.powDifficulty=%d", ParaPoWFaucetDifficulty),
fmt.Sprintf("--gracefulshutdown.waitToKillTime=%d", ParaWaitToKill),
fmt.Sprintf("--node.enablePlugins=%s", func() string {
var plugins []string
if config.Faucet {
plugins = append(plugins, "faucet")
}
if config.SyncBeacon {
plugins = append(plugins, "SyncBeacon")
}
if config.SyncBeaconFollower {
plugins = append(plugins, "SyncBeaconFollower")
}
return strings.Join(plugins[:], ",")
}()),
// define the faucet seed in case the faucet dApp is enabled
func() string {
if !config.Faucet {
return ""
}
return fmt.Sprintf("--faucet.seed=%s", genesisSeedBase58)
}(),
fmt.Sprintf("--faucet.tokensPerRequest=%d", ParaFaucetTokensPerRequest),
fmt.Sprintf("--valueLayer.snapshot.file=%s", config.SnapshotFilePath),
"--webapi.bindAddress=0.0.0.0:8080",
fmt.Sprintf("--autopeering.seed=base58:%s", config.Seed),
fmt.Sprintf("--autopeering.entryNodes=%s@%s:14626", config.EntryNodePublicKey, config.EntryNodeHost),
fmt.Sprintf("--drng.instanceId=%d", config.DRNGInstance),
fmt.Sprintf("--drng.threshold=%d", config.DRNGThreshold),
fmt.Sprintf("--drng.committeeMembers=%s", config.DRNGCommittee),
fmt.Sprintf("--drng.distributedPubKey=%s", config.DRNGDistKey),
fmt.Sprintf("--syncbeaconfollower.followNodes=%s", config.SyncBeaconFollowNodes),
fmt.Sprintf("--syncbeacon.broadcastInterval=%d", config.SyncBeaconBroadcastInterval),
"--syncbeacon.startSynced=true",
},
}
return d.CreateContainer(config.Name, containerConfig, &container.HostConfig{
Binds: []string{"goshimmer-testing-assets:/assets:rw"},
})
}
// CreateDrandMember creates a new container with the drand configuration.
func (d *DockerContainer) CreateDrandMember(name string, goShimmerAPI string, leader bool) error {
// configure drand container instance
env := []string{}
if leader {
env = append(env, "LEADER=1")
}
env = append(env, "GOSHIMMER=http://"+goShimmerAPI)
containerConfig := &container.Config{
Image: "angelocapossele/drand:latest",
ExposedPorts: nat.PortSet{
nat.Port("8000/tcp"): {},
},
Env: env,
Entrypoint: strslice.StrSlice{"/data/client-script.sh"},
}
return d.CreateContainer(name, containerConfig)
}
// CreatePumba creates a new container with Pumba configuration.
func (d *DockerContainer) CreatePumba(name string, containerName string, targetIPs []string) error {
hostConfig := &container.HostConfig{
Binds: strslice.StrSlice{"/var/run/docker.sock:/var/run/docker.sock:ro"},
}
cmd := strslice.StrSlice{
"--log-level=debug",
"netem",
"--duration=100m",
}
for _, ip := range targetIPs {
targetFlag := "--target=" + ip
cmd = append(cmd, targetFlag)
}
slice := strslice.StrSlice{
"--tc-image=gaiadocker/iproute2",
"loss",
"--percent=100",
containerName,
}
cmd = append(cmd, slice...)
containerConfig := &container.Config{
Image: "gaiaadm/pumba:0.7.2",
Cmd: cmd,
}
return d.CreateContainer(name, containerConfig, hostConfig)
}
// CreateContainer creates a new container with the given configuration.
func (d *DockerContainer) CreateContainer(name string, containerConfig *container.Config, hostConfigs ...*container.HostConfig) error {
var hostConfig *container.HostConfig
if len(hostConfigs) > 0 {
hostConfig = hostConfigs[0]
}
resp, err := d.client.ContainerCreate(context.Background(), containerConfig, hostConfig, nil, name)
if err != nil {
return err
}
d.id = resp.ID
return nil
}
// ConnectToNetwork connects a container to an existent network in the docker host.
func (d *DockerContainer) ConnectToNetwork(networkID string) error {
return d.client.NetworkConnect(context.Background(), networkID, d.id, nil)
}
// DisconnectFromNetwork disconnects a container from an existent network in the docker host.
func (d *DockerContainer) DisconnectFromNetwork(networkID string) error {
return d.client.NetworkDisconnect(context.Background(), networkID, d.id, true)
}
// Start sends a request to the docker daemon to start a container.
func (d *DockerContainer) Start() error {
return d.client.ContainerStart(context.Background(), d.id, types.ContainerStartOptions{})
}
// Remove kills and removes a container from the docker host.
func (d *DockerContainer) Remove() error {
return d.client.ContainerRemove(context.Background(), d.id, types.ContainerRemoveOptions{Force: true})
}
// Stop stops a container without terminating the process.
// The process is blocked until the container stops or the timeout expires.
func (d *DockerContainer) Stop(optionalTimeout ...time.Duration) error {
duration := 3 * time.Minute
if optionalTimeout != nil {
duration = optionalTimeout[0]
}
return d.client.ContainerStop(context.Background(), d.id, &duration)
}
// ExitStatus returns the exit status according to the container information.
func (d *DockerContainer) ExitStatus() (int, error) {
resp, err := d.client.ContainerInspect(context.Background(), d.id)
if err != nil {
return -1, err
}
return resp.State.ExitCode, nil
}
// IP returns the IP address according to the container information for the given network.
func (d *DockerContainer) IP(network string) (string, error) {
resp, err := d.client.ContainerInspect(context.Background(), d.id)
if err != nil {
return "", err
}
for name, v := range resp.NetworkSettings.Networks {
if name == network {
return v.IPAddress, nil
}
}
return "", fmt.Errorf("IP address in %s could not be determined", network)
}
// Logs returns the logs of the container as io.ReadCloser.
func (d *DockerContainer) Logs() (io.ReadCloser, error) {
options := types.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
Since: "",
Timestamps: false,
Follow: false,
Tail: "",
Details: false,
}
return d.client.ContainerLogs(context.Background(), d.id, options)
}