Skip to content
Merged
Show file tree
Hide file tree
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
9 changes: 8 additions & 1 deletion controllers/container_network_tunnel_proxy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ var (
type ContainerNetworkTunnelProxyReconcilerConfig struct {
ProcessExecutor process.Executor // Mandatory

// Directory that owns the lifetime of generated tunnel proxy image build contexts.
// Defaults to the DCP temporary directory.
BuildContextDir string

// The factory function to create a TunnelControlClient used to control the proxy pair.
// Normal execution uses "real" gRPC client, tests use a stub since most tests do not run real tunnels.
// Mandatory.
Expand Down Expand Up @@ -132,6 +136,9 @@ func NewContainerNetworkTunnelProxyReconciler(
if config.ProcessExecutor == nil {
panic("ContainerNetworkTunnelProxyReconcilerConfig.ProcessExecutor must not be nil")
}
if config.BuildContextDir == "" {
config.BuildContextDir = usvc_io.DcpTempDir()
}
if config.MakeTunnelControlClient == nil {
panic("ContainerNetworkTunnelProxyReconcilerConfig.TunnelControlClientFactory must not be nil")
}
Expand Down Expand Up @@ -1204,7 +1211,7 @@ func (r *ContainerNetworkTunnelProxyReconciler) ensureTunnelProxyPhysicalContain
return fmt.Errorf("get PhysicalContainerImage %q: %w", imageName.String(), getErr)
}

imagePlan, prepareErr := dcptun.PrepareClientProxyImageBuild(ctx)
imagePlan, prepareErr := dcptun.PrepareClientProxyImageBuild(ctx, r.config.BuildContextDir)
if prepareErr != nil {
return prepareErr
}
Expand Down
15 changes: 10 additions & 5 deletions internal/dcptun/image_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ type ClientProxyImageBuildPlan struct {

// PrepareClientProxyImageBuild creates the build input for the shared tunnel proxy
// PhysicalContainerImage.
func PrepareClientProxyImageBuild(ctx context.Context) (ClientProxyImageBuildPlan, error) {
func PrepareClientProxyImageBuild(ctx context.Context, buildContextDir string) (ClientProxyImageBuildPlan, error) {
if buildContextDir == "" {
return ClientProxyImageBuildPlan{}, fmt.Errorf("build context directory is required")
}

dcpTunClientPath, clientPathErr := dcptunClientBinaryPath()
if clientPathErr != nil {
return ClientProxyImageBuildPlan{}, fmt.Errorf("failed to get path to dcptun client binary: %w", clientPathErr)
Expand All @@ -69,7 +73,7 @@ func PrepareClientProxyImageBuild(ctx context.Context) (ClientProxyImageBuildPla
if digestErr != nil {
return ClientProxyImageBuildPlan{}, digestErr
}
buildContextArchive, contextErr := setupImageBuildContextArchive(ctx, dcpTunClientPath, dockerfileContent)
buildContextArchive, contextErr := setupImageBuildContextArchive(ctx, buildContextDir, dcpTunClientPath, dockerfileContent)
if contextErr != nil {
return ClientProxyImageBuildPlan{}, fmt.Errorf("failed to create build context archive: %w", contextErr)
}
Expand Down Expand Up @@ -99,6 +103,7 @@ func clientProxyImageName(clientBinaryHash string) string {

func setupImageBuildContextArchive(
ctx context.Context,
buildContextDir string,
dcpTunClientPath string,
dockerfileContent string,
) (*containers.ContainerBuildContextArchive, error) {
Expand All @@ -110,9 +115,9 @@ func setupImageBuildContextArchive(
if randomSuffixErr != nil {
return nil, fmt.Errorf("create random build context archive suffix: %w", randomSuffixErr)
}
// The archive lives in the DCP session directory, whose lifetime owns its cleanup.
archiveFile, openArchiveErr := usvc_io.CreateNewTempFile(
fmt.Sprintf("dcptun-build-context-%s.tar", randomSuffix),
// The caller-provided directory owns the archive lifetime.
archiveFile, openArchiveErr := usvc_io.CreateNewFile(
filepath.Join(buildContextDir, fmt.Sprintf("dcptun-build-context-%s.tar", randomSuffix)),
osutil.PermissionOnlyOwnerReadWrite,
)
if openArchiveErr != nil {
Expand Down
10 changes: 7 additions & 3 deletions internal/dcptun/image_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"context"
"io"
"os"
"path/filepath"
"strings"
"testing"

Expand All @@ -24,8 +25,9 @@ func TestPrepareClientProxyImageBuild(t *testing.T) {
t.Parallel()

dcppaths.EnableTestPathProbing()
buildContextDir := t.TempDir()

plan, prepareErr := dcptun.PrepareClientProxyImageBuild(context.Background())
plan, prepareErr := dcptun.PrepareClientProxyImageBuild(context.Background(), buildContextDir)
require.NoError(t, prepareErr)

const expectedTagPrefix = "dcptun_developer_ms:"
Expand All @@ -34,6 +36,7 @@ func TestPrepareClientProxyImageBuild(t *testing.T) {
require.NotNil(t, plan.BuildContextArchive)
require.NotEmpty(t, plan.BuildContextDigest)
require.NotEmpty(t, plan.BuildContextArchive.Source)
require.Equal(t, buildContextDir, filepath.Dir(plan.BuildContextArchive.Source))
require.NotEmpty(t, plan.BuildContextArchive.SHA256)
require.NotEqual(t, "sha256:"+plan.BuildContextArchive.SHA256, plan.BuildContextDigest)
require.Empty(t, plan.BuildContextArchive.RawContents)
Expand All @@ -42,9 +45,10 @@ func TestPrepareClientProxyImageBuild(t *testing.T) {
require.NoError(t, os.Remove(plan.BuildContextArchive.Source))
})

secondPlan, secondPrepareErr := dcptun.PrepareClientProxyImageBuild(context.Background())
secondPlan, secondPrepareErr := dcptun.PrepareClientProxyImageBuild(context.Background(), buildContextDir)
require.NoError(t, secondPrepareErr)
require.Equal(t, plan.BuildContextDigest, secondPlan.BuildContextDigest)
require.Equal(t, buildContextDir, filepath.Dir(secondPlan.BuildContextArchive.Source))
t.Cleanup(func() {
require.NoError(t, os.Remove(secondPlan.BuildContextArchive.Source))
})
Expand Down Expand Up @@ -77,6 +81,6 @@ func TestPrepareClientProxyImageBuildHonorsCancellation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()

_, prepareErr := dcptun.PrepareClientProxyImageBuild(ctx)
_, prepareErr := dcptun.PrepareClientProxyImageBuild(ctx, t.TempDir())
require.ErrorIs(t, prepareErr, context.Canceled)
}
1 change: 1 addition & 0 deletions test/integration/advanced_test_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ func StartAdvancedTestEnvironmentWithOptions(
if inclCtrl&ContainerNetworkTunnelProxyController != 0 {
tprOpts := controllers.ContainerNetworkTunnelProxyReconcilerConfig{
ProcessExecutor: pe,
BuildContextDir: sessionFolder,
MakeTunnelControlClient: dcptunproto.NewTunnelControlClient,
MaxTunnelPreparationAttempts: 2,
}
Expand Down
20 changes: 4 additions & 16 deletions test/integration/container_network_tunnel_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,26 +185,14 @@ func TestTunnelProxyRunningStatus(t *testing.T) {
dcppaths.EnableTestPathProbing()
const testName = "test-tunnel-proxy-running-status"

buildContextDir, mkdirErr := os.MkdirTemp("", "dcp-tunnel-")
require.NoError(t, mkdirErr)
t.Cleanup(func() {
require.NoError(t, os.RemoveAll(buildContextDir))
})
originalDcpTempDir := usvc_io.DcpTempDir
usvc_io.DcpTempDir = func() string {
return buildContextDir
}
t.Cleanup(func() {
usvc_io.DcpTempDir = originalDcpTempDir
})

includedControllers := ServiceController | NetworkController | ContainerNetworkTunnelProxyController
serverInfo, teInfo, startupErr := StartTestEnvironment(ctx, includedControllers, t.Name(), t.TempDir())
require.NoError(t, startupErr, "Failed to start the API server")
defer shutdownTestEnvironment(serverInfo, cancel)
testContainerOrchestrator, ok := serverInfo.ContainerOrchestrator.(*ctrl_testutil.TestContainerOrchestrator)
require.True(t, ok)
imagePlan, imagePlanErr := dcptun.PrepareClientProxyImageBuild(ctx)
buildContextDir := teInfo.SessionFolder
imagePlan, imagePlanErr := dcptun.PrepareClientProxyImageBuild(ctx, buildContextDir)
require.NoError(t, imagePlanErr)
require.NoError(t, os.Remove(imagePlan.BuildContextArchive.Source))
releaseImageBuild := testContainerOrchestrator.BlockBuildImage(imagePlan.Image)
Expand Down Expand Up @@ -316,7 +304,7 @@ func TestTunnelProxyRunningStatus(t *testing.T) {
require.NoError(t, globErr)
require.Equal(t, []string{physicalImages.Items[0].Spec.Image.Build.ContextArchive.Source}, buildContextFiles)
t.Cleanup(func() {
require.NoError(t, os.Remove(physicalImages.Items[0].Spec.Image.Build.ContextArchive.Source))
require.NoFileExists(t, physicalImages.Items[0].Spec.Image.Build.ContextArchive.Source)
})
require.Equal(t, apiv2.PhysicalContainerImagePhaseReady, physicalImages.Items[0].Status.Phase)
require.Equal(t, 1, testContainerOrchestrator.BuildImageCallCount(updatedTunnelProxy.Status.ClientProxyContainerImage))
Expand Down Expand Up @@ -509,7 +497,7 @@ func TestTunnelProxyCleanup(t *testing.T) {
require.Empty(t, physicalImage.Spec.Image.Build.ContextArchive.RawContents)
require.FileExists(t, physicalImage.Spec.Image.Build.ContextArchive.Source)
t.Cleanup(func() {
require.NoError(t, os.Remove(physicalImage.Spec.Image.Build.ContextArchive.Source))
require.NoFileExists(t, physicalImage.Spec.Image.Build.ContextArchive.Source)
})

t.Logf("Deleting ContainerNetworkTunnelProxy object '%s'", tunnelProxy.ObjectMeta.Name)
Expand Down
3 changes: 3 additions & 0 deletions test/integration/standard_test_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type TestEnvironmentInfo struct {
StateStore *statestore.Store
ResourceLeaseOwner process.ProcessHandle
Log logr.Logger
SessionFolder string
}

type TestEnvironmentOptions struct {
Expand Down Expand Up @@ -377,6 +378,7 @@ func StartTestEnvironmentWithOptions(
tcc = ctrl_testutil.NewTestTunnelControlClient()
tprOpts := controllers.ContainerNetworkTunnelProxyReconcilerConfig{
ProcessExecutor: pex,
BuildContextDir: sessionFolder,
MakeTunnelControlClient: func(_ grpc.ClientConnInterface) dcptunproto.TunnelControlClient { return tcc },
MaxTunnelPreparationAttempts: 2,
}
Expand Down Expand Up @@ -414,6 +416,7 @@ func StartTestEnvironmentWithOptions(
StateStore: stateStore,
ResourceLeaseOwner: leaseOwner,
Log: log,
SessionFolder: sessionFolder,
}
return serverInfo, teInfo, nil
}
Loading