Skip to content

Commit

Permalink
Merge pull request #1009 from jonjohnsonjr/k8s
Browse files Browse the repository at this point in the history
Split pkg/container up into smaller packages
  • Loading branch information
jonjohnsonjr authored Feb 10, 2024
2 parents e2d4f3e + c03ff93 commit 8269921
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 114 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022 Chainguard, Inc.
// Copyright 2024 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,60 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package container
package contextreader

import (
"bytes"
"context"
"io"
"log/slog"
"sync"

"github.com/chainguard-dev/clog"
)

func logWriters(ctx context.Context) (stdout, stderr io.WriteCloser) {
return logWriter(ctx, slog.LevelInfo), logWriter(ctx, slog.LevelWarn)
}

func logWriter(ctx context.Context, level slog.Level) io.WriteCloser {
log := clog.FromContext(ctx)
f := log.Info
if level == slog.LevelWarn {
f = log.Warn
}
buf := new(bytes.Buffer)
return &levelWriter{f, buf}
}

type levelWriter struct {
log func(string, ...any)
buf *bytes.Buffer
}

func (l *levelWriter) Write(p []byte) (int, error) {
n, err := l.buf.Write(p)

for {
line, lerr := l.buf.ReadString('\n')
if lerr != nil {
l.buf.WriteString(line)
break
}
line = line[:len(line)-1] // trim the newline at the end
l.log(line)
}

return n, err
}

func (l *levelWriter) Close() error {
if l.buf.Len() != 0 {
l.log(l.buf.String())
}
return nil
}

type contextReader struct {
ctx context.Context
r io.Reader
Expand All @@ -78,7 +32,7 @@ type contextReader struct {
done chan struct{}
}

func newContextReader(ctx context.Context, r io.Reader) *contextReader {
func New(ctx context.Context, r io.Reader) io.Reader {
return &contextReader{
ctx: ctx,
r: r,
Expand Down
53 changes: 53 additions & 0 deletions internal/logwriter/logwriter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2024 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package logwriter

import (
"bytes"
"io"
)

func New(log func(string, ...any)) io.WriteCloser {
buf := new(bytes.Buffer)
return &levelWriter{log, buf}
}

type levelWriter struct {
log func(string, ...any)
buf *bytes.Buffer
}

func (l *levelWriter) Write(p []byte) (int, error) {
n, err := l.buf.Write(p)

for {
line, lerr := l.buf.ReadString('\n')
if lerr != nil {
l.buf.WriteString(line)
break
}
line = line[:len(line)-1] // trim the newline at the end
l.log(line)
}

return n, err
}

func (l *levelWriter) Close() error {
if l.buf.Len() != 0 {
l.log(l.buf.String())
}
return nil
}
8 changes: 5 additions & 3 deletions pkg/cli/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
apko_types "chainguard.dev/apko/pkg/build/types"
"chainguard.dev/melange/pkg/build"
"chainguard.dev/melange/pkg/container"
"chainguard.dev/melange/pkg/container/docker"
"chainguard.dev/melange/pkg/container/k8s"
"github.com/chainguard-dev/clog"
"github.com/spf13/cobra"
"go.opentelemetry.io/otel"
Expand Down Expand Up @@ -184,9 +186,9 @@ func getRunner(ctx context.Context, runner string) (container.Runner, error) {
case "bubblewrap":
return container.BubblewrapRunner(), nil
case "docker":
return container.DockerRunner(ctx)
return docker.NewRunner(ctx)
case "kubernetes":
return container.KubernetesRunner(ctx)
return k8s.NewRunner(ctx)
default:
return nil, fmt.Errorf("unknown runner: %s", runner)
}
Expand All @@ -199,7 +201,7 @@ func getRunner(ctx context.Context, runner string) (container.Runner, error) {
// darwin is the same as default, but we want to keep it explicit
fallthrough
default:
return container.DockerRunner(ctx)
return docker.NewRunner(ctx)
}
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/container/bubblewrap_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

apko_build "chainguard.dev/apko/pkg/build"
apko_types "chainguard.dev/apko/pkg/build/types"
"chainguard.dev/melange/internal/logwriter"
"github.com/chainguard-dev/clog"
v1 "github.com/google/go-containerregistry/pkg/v1"
"go.opentelemetry.io/otel"
Expand Down Expand Up @@ -57,7 +58,8 @@ func (bw *bubblewrap) Name() string {
func (bw *bubblewrap) Run(ctx context.Context, cfg *Config, args ...string) error {
execCmd := bw.cmd(ctx, cfg, args...)

stdout, stderr := logWriters(ctx)
log := clog.FromContext(ctx)
stdout, stderr := logwriter.New(log.Info), logwriter.New(log.Warn)
defer stdout.Close()
defer stderr.Close()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package container
package docker

import (
"context"
Expand All @@ -26,6 +26,9 @@ import (
apko_build "chainguard.dev/apko/pkg/build"
apko_oci "chainguard.dev/apko/pkg/build/oci"
apko_types "chainguard.dev/apko/pkg/build/types"
"chainguard.dev/melange/internal/contextreader"
"chainguard.dev/melange/internal/logwriter"
mcontainer "chainguard.dev/melange/pkg/container"
"github.com/chainguard-dev/clog"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api/types"
Expand All @@ -38,17 +41,21 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
)

var _ Debugger = (*docker)(nil)
var _ mcontainer.Debugger = (*docker)(nil)

const DockerName = "docker"
const (
DockerName = "docker"

runnerWorkdir = "/home/build"
)

// docker is a Runner implementation that uses the docker library.
type docker struct {
cli *client.Client
}

// DockerRunner returns a Docker Runner implementation.
func DockerRunner(ctx context.Context) (Runner, error) {
// NewRunner returns a Docker Runner implementation.
func NewRunner(ctx context.Context) (mcontainer.Runner, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
Expand All @@ -69,7 +76,7 @@ func (dk *docker) Close() error {

// StartPod starts a pod for supporting a Docker task, if
// necessary.
func (dk *docker) StartPod(ctx context.Context, cfg *Config) error {
func (dk *docker) StartPod(ctx context.Context, cfg *mcontainer.Config) error {
log := clog.FromContext(ctx)

ctx, span := otel.Tracer("melange").Start(ctx, "docker.StartPod")
Expand Down Expand Up @@ -131,7 +138,7 @@ func (dk *docker) StartPod(ctx context.Context, cfg *Config) error {

// TerminatePod terminates a pod for supporting a Docker task,
// if necessary.
func (dk *docker) TerminatePod(ctx context.Context, cfg *Config) error {
func (dk *docker) TerminatePod(ctx context.Context, cfg *mcontainer.Config) error {
log := clog.FromContext(ctx)
ctx, span := otel.Tracer("melange").Start(ctx, "docker.TerminatePod")
defer span.End()
Expand Down Expand Up @@ -164,7 +171,7 @@ func (dk *docker) TestUsability(ctx context.Context) bool {
}

// OCIImageLoader create a loader to load an OCI image into the docker daemon.
func (dk *docker) OCIImageLoader() Loader {
func (dk *docker) OCIImageLoader() mcontainer.Loader {
return &dockerLoader{
cli: dk.cli,
}
Expand All @@ -182,20 +189,21 @@ func (dk *docker) waitForCommand(ctx context.Context, r io.Reader) error {
ctx, span := otel.Tracer("melange").Start(ctx, "waitForCommand")
defer span.End()

stdout, stderr := logWriters(ctx)
log := clog.FromContext(ctx)
stdout, stderr := logwriter.New(log.Info), logwriter.New(log.Warn)
defer stdout.Close()
defer stderr.Close()

// Wrap this in a contextReader so we respond to cancel.
ctxr := newContextReader(ctx, r)
ctxr := contextreader.New(ctx, r)

_, err := stdcopy.StdCopy(stdout, stderr, ctxr)
return err
}

// Run runs a Docker task given a Config and command string.
// The resultant filesystem can be read from the io.ReadCloser
func (dk *docker) Run(ctx context.Context, cfg *Config, args ...string) error {
func (dk *docker) Run(ctx context.Context, cfg *mcontainer.Config, args ...string) error {
if cfg.PodID == "" {
return fmt.Errorf("pod not running")
}
Expand Down Expand Up @@ -246,7 +254,7 @@ func (dk *docker) Run(ctx context.Context, cfg *Config, args ...string) error {
}
}

func (dk *docker) Debug(ctx context.Context, cfg *Config, args ...string) error {
func (dk *docker) Debug(ctx context.Context, cfg *mcontainer.Config, args ...string) error {
if cfg.PodID == "" {
return fmt.Errorf("pod not running")
}
Expand Down Expand Up @@ -302,7 +310,7 @@ func (dk *docker) Debug(ctx context.Context, cfg *Config, args ...string) error
defer interm.RestoreTerminal()

// Allows us to cancel the Read().
ctxr := newContextReader(inctx, interm)
ctxr := contextreader.New(inctx, interm)

if _, err := io.Copy(attachResp.Conn, ctxr); err != nil {
return fmt.Errorf("copy in : %w", err)
Expand Down Expand Up @@ -344,7 +352,7 @@ func (dk *docker) Debug(ctx context.Context, cfg *Config, args ...string) error

// WorkspaceTar implements Runner
// This is a noop for Docker, which uses bind-mounts to manage the workspace
func (dk *docker) WorkspaceTar(ctx context.Context, cfg *Config) (io.ReadCloser, error) {
func (dk *docker) WorkspaceTar(ctx context.Context, cfg *mcontainer.Config) (io.ReadCloser, error) {
return nil, nil
}

Expand Down
Loading

0 comments on commit 8269921

Please sign in to comment.