Skip to content

Commit

Permalink
finish swapping out DNS with static host config
Browse files Browse the repository at this point in the history
A few things had to be sacrificed here:

* HTTP and Git APIs can no longer use services. It doesn't seem possible
  to do this with static hosts. This API was always experimental and
  only used in tests.
* A lazy: true param has been added to Container.File and
  Container.Directory, which is now used instead of the Git/HTTP APIs to
  test lazy service starting.
* It is no longer possible to reach services from within a Dockerfile
  build. This was also experimental and it's unlikely that it was ever
  used.

Signed-off-by: Alex Suraci <suraci.alex@gmail.com>
  • Loading branch information
vito committed Jul 18, 2023
1 parent fcfee59 commit 85f896e
Show file tree
Hide file tree
Showing 20 changed files with 420 additions and 334 deletions.
55 changes: 55 additions & 0 deletions cmd/shim/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package main

import (
"fmt"
"io"
"net"
"strings"
)

func ip(args []string) error {
Expand Down Expand Up @@ -51,3 +53,56 @@ func containerIP() (net.IP, error) {

return nil, fmt.Errorf("could not determine container IP (must be in %s)", cidr)
}

func ipExchange() (string, error) {
ip, err := containerIP()
if err != nil {
return "", err
}

l, err := net.Listen("tcp", ip.String()+":0")
if err != nil {
return "", err
}

// print checker's IP so we can pass it to the service for collecting the
// service IP
fmt.Println(l.Addr())

conn, err := l.Accept()
if err != nil {
return "", err
}

svcIPPayload, err := io.ReadAll(conn)
if err != nil {
return "", err
}

svcIP := strings.TrimSpace(string(svcIPPayload))

// print service IP; this is read by the outer health check process and
// stored for passing to clients
fmt.Println(svcIP)

return svcIP, nil
}

func reportIP(addr string) error {
ip, err := containerIP()
if err != nil {
return fmt.Errorf("get container IP: %w", err)
}

conn, err := net.Dial("tcp", addr)
if err != nil {
return fmt.Errorf("dial: %w", err)
}

_, err = fmt.Fprintln(conn, ip.String())
if err != nil {
return fmt.Errorf("write: %w", err)
}

return conn.Close()
}
38 changes: 26 additions & 12 deletions cmd/shim/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,6 @@ func internalCommand() int {
args := os.Args[2:]

switch cmd {
case "ip":
if err := ip(args); err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
return 0
case "check":
if err := check(args); err != nil {
fmt.Fprintln(os.Stderr, err)
Expand All @@ -96,10 +90,15 @@ func internalCommand() int {

func check(args []string) error {
if len(args) == 0 {
return fmt.Errorf("usage: check <host> port/tcp [port/udp ...]")
return fmt.Errorf("usage: check port/tcp [port/udp ...]")
}

host, ports := args[0], args[1:]
host, err := ipExchange()
if err != nil {
return fmt.Errorf("exchange IPs: %w", err)
}

ports := args

for _, port := range ports {
port, network, ok := strings.Cut(port, "/")
Expand All @@ -109,14 +108,14 @@ func check(args []string) error {

pollAddr := net.JoinHostPort(host, port)

fmt.Println("polling for port", pollAddr)
fmt.Fprintln(os.Stderr, "polling for port", pollAddr)

reached, err := pollForPort(network, pollAddr)
if err != nil {
return fmt.Errorf("poll %s: %w", pollAddr, err)
}

fmt.Println("port is up at", reached)
fmt.Fprintln(os.Stderr, "port is up at", reached)
}

return nil
Expand Down Expand Up @@ -163,6 +162,14 @@ func shim() int {
return 1
}

checkerAddr, found := internalEnv("_DAGGER_CHECKER_ADDR")
if found {
if err := reportIP(checkerAddr); err != nil {
fmt.Fprintln(os.Stderr, "report container IP:", err)
return 1
}
}

name := os.Args[1]
args := []string{}
if len(os.Args) > 2 {
Expand Down Expand Up @@ -392,12 +399,19 @@ func setupBundle() int {
break
}
}
// We're running an internal shim command, i.e. a service health check

for _, env := range spec.Process.Env {
// We're running an internal shim command, i.e. a service health check
if strings.HasPrefix(env, "_DAGGER_INTERNAL_COMMAND=") {
isDaggerExec = true
break
}
// We're running a service, which needs to report its IP to the health
// checker as part of the IP exchange dance
if strings.HasPrefix(env, "_DAGGER_CHECKER_ADDR=") {
isDaggerExec = true
break
}
}

if isDaggerExec {
Expand Down Expand Up @@ -550,7 +564,7 @@ func appendHostAlias(hostsFilePath string, env string, serviceIPs map[string]str

ip, found := serviceIPs[target]
if !found {
return fmt.Errorf("service %s not found in _DAGGER_SERVICES", target)
return fmt.Errorf("service %s not found in _DAGGER_SERVICES: %v", target, serviceIPs)
}

hostsFile, err := os.OpenFile(hostsFilePath, os.O_APPEND|os.O_WRONLY, 0o777)
Expand Down
42 changes: 29 additions & 13 deletions core/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -770,12 +770,16 @@ func (container *Container) WithSecretVariable(ctx context.Context, name string,
return container, nil
}

func (container *Container) Directory(ctx context.Context, gw bkgw.Client, dirPath string) (*Directory, error) {
func (container *Container) Directory(ctx context.Context, gw bkgw.Client, dirPath string, lazy bool) (*Directory, error) {
dir, _, err := locatePath(ctx, container, dirPath, NewDirectory)
if err != nil {
return nil, err
}

if lazy {
return dir, nil
}

// check that the directory actually exists so the user gets an error earlier
// rather than when the dir is used
info, err := dir.Stat(ctx, gw, ".")
Expand All @@ -790,12 +794,16 @@ func (container *Container) Directory(ctx context.Context, gw bkgw.Client, dirPa
return dir, nil
}

func (container *Container) File(ctx context.Context, gw bkgw.Client, filePath string) (*File, error) {
func (container *Container) File(ctx context.Context, gw bkgw.Client, filePath string, lazy bool) (*File, error) {
file, _, err := locatePath(ctx, container, filePath, NewFile)
if err != nil {
return nil, err
}

if lazy {
return file, nil
}

// check that the file actually exists so the user gets an error earlier
// rather than when the file is used
info, err := file.Stat(ctx, gw)
Expand Down Expand Up @@ -1042,6 +1050,23 @@ func (container *Container) command(opts ContainerExecOpts) ([]string, error) {
return args, nil
}

func metaMount(stdin string) (llb.State, string) {
// because the shim might run as non-root, we need to make a world-writable
// directory first and then make it the base of the /dagger mount point.
//
// TODO(vito): have the shim exec as the other user instead?
meta := llb.Mkdir(metaSourcePath, 0o777)
if stdin != "" {
meta = meta.Mkfile(path.Join(metaSourcePath, "stdin"), 0o600, []byte(stdin))
}

return llb.Scratch().File(
meta,
llb.WithCustomName(internalPrefix+"creating dagger metadata"),
),
metaSourcePath
}

func (container *Container) WithExec(ctx context.Context, gw bkgw.Client, progSock *Socket, defaultPlatform specs.Platform, opts ContainerExecOpts) (*Container, error) { //nolint:gocyclo
container = container.Clone()

Expand Down Expand Up @@ -1109,20 +1134,11 @@ func (container *Container) WithExec(ctx context.Context, gw bkgw.Client, progSo
llb.SecretAsEnv(true)))
}

// because the shim might run as non-root, we need to make a world-writable
// directory first and then make it the base of the /dagger mount point.
//
// TODO(vito): have the shim exec as the other user instead?
meta := llb.Mkdir(metaSourcePath, 0o777)
if opts.Stdin != "" {
meta = meta.Mkfile(path.Join(metaSourcePath, "stdin"), 0o600, []byte(opts.Stdin))
}
metaSt, metaSourcePath := metaMount(opts.Stdin)

// create /dagger mount point for the shim to write to
runOpts = append(runOpts,
llb.AddMount(metaMountDestPath,
llb.Scratch().File(meta, llb.WithCustomName(internalPrefix+"creating dagger metadata")),
llb.SourcePath(metaSourcePath)))
llb.AddMount(metaMountDestPath, metaSt, llb.SourcePath(metaSourcePath)))

if opts.RedirectStdout != "" {
runOpts = append(runOpts, llb.AddEnv("_DAGGER_REDIRECT_STDOUT", opts.RedirectStdout))
Expand Down
5 changes: 4 additions & 1 deletion core/integration/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ func TestGit(t *testing.T) {
}

func TestGitSSHAuthSock(t *testing.T) {
t.Skip("this is hard to test now that Git can't reach services")

t.Parallel()
checkNotDisabled(t, engine.ServicesDNSEnvName)

Expand Down Expand Up @@ -162,7 +164,8 @@ sleep infinity
require.NoError(t, err)

repoURL := fmt.Sprintf("ssh://root@%s:%d/root/repo", sshHost, sshPort)
entries, err := c.Git(repoURL, dagger.GitOpts{ExperimentalServiceHost: sshSvc}).
// XXX(vito):, dagger.GitOpts{ExperimentalServiceHost: sshSvc}).
entries, err := c.Git(repoURL).
Branch("main").
Tree(dagger.GitRefTreeOpts{
SSHKnownHosts: fmt.Sprintf("[%s]:%d %s", sshHost, sshPort, strings.TrimSpace(hostPubKey)),
Expand Down
19 changes: 0 additions & 19 deletions core/integration/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package core
import (
"testing"

"dagger.io/dagger"
"github.com/dagger/dagger/internal/engine"
"github.com/stretchr/testify/require"
)

Expand All @@ -25,20 +23,3 @@ func TestHTTP(t *testing.T) {
require.NoError(t, err)
require.Contains(t, contents, "Dagger")
}

func TestHTTPService(t *testing.T) {
checkNotDisabled(t, engine.ServicesDNSEnvName)

t.Parallel()

c, ctx := connect(t)
defer c.Close()

svc, url := httpService(ctx, t, c, "Hello, world!")

contents, err := c.HTTP(url, dagger.HTTPOpts{
ExperimentalServiceHost: svc,
}).Contents(ctx)
require.NoError(t, err)
require.Equal(t, contents, "Hello, world!")
}
Loading

0 comments on commit 85f896e

Please sign in to comment.