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

Changes for slim rly images #349

Merged
merged 2 commits into from
Dec 1, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 4 additions & 142 deletions relayer/docker.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package relayer

import (
"archive/tar"
"bytes"
"context"
"fmt"
Expand Down Expand Up @@ -135,13 +134,9 @@ func (r *DockerRelayer) AddChainConfiguration(ctx context.Context, rep ibc.Relay
return fmt.Errorf("failed to generate config content: %w", err)
}

tar, err := r.generateConfigTar(chainConfigFile, configContent)
if err != nil {
return fmt.Errorf("generating tar for configuration: %w", err)
}

if err := r.untarIntoNodeHome(ctx, tar); err != nil {
return err // Already wrapped.
fw := dockerutil.NewFileWriter(r.log, r.client, r.testName)
if err := fw.WriteFile(ctx, r.volumeName, chainConfigFile, configContent); err != nil {
return fmt.Errorf("failed to rly config: %w", err)
}

cmd := r.c.AddChainConfiguration(chainConfigContainerFilePath, r.HomeDir())
Expand All @@ -155,40 +150,6 @@ func (r *DockerRelayer) AddChainConfiguration(ctx context.Context, rep ibc.Relay
return res.Err
}

// generateConfigTar returns an io.Reader containing the content of a tar archive
// which contains only the initial relayer config content.
func (r *DockerRelayer) generateConfigTar(relativeConfigPath string, content []byte) (io.Reader, error) {
var buf bytes.Buffer

// Although the docker module offers a "pkg/archive" package,
// there is no simple support for setting users and permissions.
// That package also brings in a surprising number of dependencies.
//
// Instead, just use a plain tar instance from the standard library.
tw := tar.NewWriter(&buf)
if err := tw.WriteHeader(&tar.Header{
Name: relativeConfigPath,

Size: int64(len(content)),
Mode: 0600,
Uname: r.c.DockerUser(),

ModTime: time.Now(),

Format: tar.FormatPAX,
}); err != nil {
return nil, fmt.Errorf("writing config file to tar: %w", err)
}
if _, err := tw.Write(content); err != nil {
return nil, fmt.Errorf("writing config content to tar: %w", err)
}
if err := tw.Close(); err != nil {
return nil, fmt.Errorf("closing tar writer: %w", err)
}

return &buf, nil
}

func (r *DockerRelayer) AddKey(ctx context.Context, rep ibc.RelayerExecReporter, chainID, keyName string) (ibc.Wallet, error) {
cmd := r.c.AddKey(chainID, keyName, r.HomeDir())

Expand Down Expand Up @@ -498,9 +459,7 @@ func (r *DockerRelayer) Bind() []string {

// HomeDir returns the home directory of the relayer on the underlying Docker container's filesystem.
func (r *DockerRelayer) HomeDir() string {
// Relayer writes to these files, so /var seems like a reasonable root.
// https://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/var.html
return "/var/relayer-" + r.c.Name()
return "/home/relayer"
}

func (r *DockerRelayer) HostName(pathName string) string {
Expand All @@ -511,103 +470,6 @@ func (r *DockerRelayer) UseDockerNetwork() bool {
return true
}

// untarIntoNodeHome untars the given io.Reader into r's NodeHome() directory.
func (r *DockerRelayer) untarIntoNodeHome(ctx context.Context, tar io.Reader) error {
return r.runOneOff(ctx, oneOffOptions{
ContainerNameDetail: "untar-chown",
Entrypoint: []string{},
Cmd: []string{"chown", "-R", r.c.DockerUser(), r.HomeDir()},
User: dockerutil.GetRootUserString(),
TarContent: tar,
})
}

// oneOffOptions indicate how to configure the container for a one-off job.
type oneOffOptions struct {
// Very short description of this container's purpose.
ContainerNameDetail string

// The entrypoint and command to use on the container.
Entrypoint, Cmd []string

// User for when the container runs.
User string

// If set, will be copied into the docker container into the NodeHome directory.
TarContent io.Reader
}

func (r *DockerRelayer) runOneOff(ctx context.Context, opts oneOffOptions) error {
containerName := r.Name() + "-" + opts.ContainerNameDetail + "-" + dockerutil.RandLowerCaseLetterString(5)
cc, err := r.client.ContainerCreate(
ctx,
&container.Config{
// Always use the main container image,
// because oftentimes this depends on the presence of the relayer user.
Image: r.containerImage().Ref(),

Entrypoint: opts.Entrypoint,
Cmd: opts.Cmd,

Hostname: r.HostName(containerName),
User: opts.User,

Labels: map[string]string{dockerutil.CleanupLabel: r.testName},
},
&container.HostConfig{
Binds: r.Bind(),
AutoRemove: false,
},
nil, // No network config in the one-off jobs for now. Could move to an option if we need it.
nil,
containerName,
)
if err != nil {
return fmt.Errorf("creating container for %s: %w", opts.ContainerNameDetail, err)
}
defer func() {
if err := r.client.ContainerRemove(ctx, cc.ID, types.ContainerRemoveOptions{Force: true}); err != nil {
r.log.Info(
"Failed to remove one-off container",
zap.String("container_name_detail", opts.ContainerNameDetail),
zap.String("container_id", cc.ID),
zap.Error(err),
)
}
}()

if opts.TarContent != nil {
// It is safe to copy into the container before starting it.
if err := r.client.CopyToContainer(
ctx,
cc.ID,
r.HomeDir(),
opts.TarContent,
types.CopyToContainerOptions{},
); err != nil {
return fmt.Errorf("copying tar to one-off %s container: %w", opts.ContainerNameDetail, err)
}
}

if err := r.client.ContainerStart(ctx, cc.ID, types.ContainerStartOptions{}); err != nil {
return fmt.Errorf("starting one-off %s container: %w", opts.ContainerNameDetail, err)
}

waitCh, errCh := r.client.ContainerWait(ctx, cc.ID, container.WaitConditionNotRunning)
select {
case <-ctx.Done():
return ctx.Err()
case err := <-errCh:
return err
case res := <-waitCh:
if res.Error != nil {
return fmt.Errorf("waiting for one-off %s container: %s", opts.ContainerNameDetail, res.Error.Message)
}
}

return nil
}

type RelayerCommander interface {
// Name is the name of the relayer, e.g. "rly" or "hermes".
Name() string
Expand Down