github.com/YousefHaggyHeroku/pack@v1.5.5/internal/build/phase_config_provider.go (about)

     1  package build
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/docker/docker/api/types/container"
     8  
     9  	"github.com/YousefHaggyHeroku/pack/logging"
    10  )
    11  
    12  const (
    13  	linuxContainerAdmin   = "root"
    14  	windowsContainerAdmin = "ContainerAdministrator"
    15  	platformAPIEnvVar     = "CNB_PLATFORM_API"
    16  )
    17  
    18  type PhaseConfigProviderOperation func(*PhaseConfigProvider)
    19  
    20  type PhaseConfigProvider struct {
    21  	ctrConf      *container.Config
    22  	hostConf     *container.HostConfig
    23  	name         string
    24  	os           string
    25  	containerOps []ContainerOperation
    26  	infoWriter   io.Writer
    27  	errorWriter  io.Writer
    28  }
    29  
    30  func NewPhaseConfigProvider(name string, lifecycleExec *LifecycleExecution, ops ...PhaseConfigProviderOperation) *PhaseConfigProvider {
    31  	provider := &PhaseConfigProvider{
    32  		ctrConf:     new(container.Config),
    33  		hostConf:    new(container.HostConfig),
    34  		name:        name,
    35  		os:          lifecycleExec.os,
    36  		infoWriter:  logging.GetWriterForLevel(lifecycleExec.logger, logging.InfoLevel),
    37  		errorWriter: logging.GetWriterForLevel(lifecycleExec.logger, logging.ErrorLevel),
    38  	}
    39  
    40  	provider.ctrConf.Image = lifecycleExec.opts.Builder.Name()
    41  	provider.ctrConf.Labels = map[string]string{"author": "pack"}
    42  
    43  	if lifecycleExec.os == "windows" {
    44  		provider.hostConf.Isolation = container.IsolationProcess
    45  	}
    46  
    47  	ops = append(ops,
    48  		WithEnv(fmt.Sprintf("%s=%s", platformAPIEnvVar, lifecycleExec.platformAPI.String())),
    49  		WithLifecycleProxy(lifecycleExec),
    50  		WithBinds([]string{
    51  			fmt.Sprintf("%s:%s", lifecycleExec.layersVolume, lifecycleExec.mountPaths.layersDir()),
    52  			fmt.Sprintf("%s:%s", lifecycleExec.appVolume, lifecycleExec.mountPaths.appDir()),
    53  		}...),
    54  	)
    55  
    56  	for _, op := range ops {
    57  		op(provider)
    58  	}
    59  
    60  	provider.ctrConf.Cmd = append([]string{"/cnb/lifecycle/" + name}, provider.ctrConf.Cmd...)
    61  
    62  	return provider
    63  }
    64  
    65  func (p *PhaseConfigProvider) ContainerConfig() *container.Config {
    66  	return p.ctrConf
    67  }
    68  
    69  func (p *PhaseConfigProvider) ContainerOps() []ContainerOperation {
    70  	return p.containerOps
    71  }
    72  
    73  func (p *PhaseConfigProvider) HostConfig() *container.HostConfig {
    74  	return p.hostConf
    75  }
    76  
    77  func (p *PhaseConfigProvider) Name() string {
    78  	return p.name
    79  }
    80  
    81  func (p *PhaseConfigProvider) ErrorWriter() io.Writer {
    82  	return p.errorWriter
    83  }
    84  
    85  func (p *PhaseConfigProvider) InfoWriter() io.Writer {
    86  	return p.infoWriter
    87  }
    88  
    89  func WithArgs(args ...string) PhaseConfigProviderOperation {
    90  	return func(provider *PhaseConfigProvider) {
    91  		provider.ctrConf.Cmd = append(provider.ctrConf.Cmd, args...)
    92  	}
    93  }
    94  
    95  // WithFlags differs from WithArgs as flags are always prepended
    96  func WithFlags(flags ...string) PhaseConfigProviderOperation {
    97  	return func(provider *PhaseConfigProvider) {
    98  		provider.ctrConf.Cmd = append(flags, provider.ctrConf.Cmd...)
    99  	}
   100  }
   101  
   102  func WithBinds(binds ...string) PhaseConfigProviderOperation {
   103  	return func(provider *PhaseConfigProvider) {
   104  		provider.hostConf.Binds = append(provider.hostConf.Binds, binds...)
   105  	}
   106  }
   107  
   108  func WithDaemonAccess() PhaseConfigProviderOperation {
   109  	return func(provider *PhaseConfigProvider) {
   110  		WithRoot()(provider)
   111  		bind := "/var/run/docker.sock:/var/run/docker.sock"
   112  		if provider.os == "windows" {
   113  			bind = `\\.\pipe\docker_engine:\\.\pipe\docker_engine`
   114  		}
   115  		provider.hostConf.Binds = append(provider.hostConf.Binds, bind)
   116  	}
   117  }
   118  
   119  func WithEnv(envs ...string) PhaseConfigProviderOperation {
   120  	return func(provider *PhaseConfigProvider) {
   121  		provider.ctrConf.Env = append(provider.ctrConf.Env, envs...)
   122  	}
   123  }
   124  
   125  func WithImage(image string) PhaseConfigProviderOperation {
   126  	return func(provider *PhaseConfigProvider) {
   127  		provider.ctrConf.Image = image
   128  	}
   129  }
   130  
   131  // WithLogPrefix sets a prefix for logs produced by this phase
   132  func WithLogPrefix(prefix string) PhaseConfigProviderOperation {
   133  	return func(provider *PhaseConfigProvider) {
   134  		if prefix != "" {
   135  			provider.infoWriter = logging.NewPrefixWriter(provider.infoWriter, prefix)
   136  			provider.errorWriter = logging.NewPrefixWriter(provider.errorWriter, prefix)
   137  		}
   138  	}
   139  }
   140  
   141  func WithLifecycleProxy(lifecycleExec *LifecycleExecution) PhaseConfigProviderOperation {
   142  	return func(provider *PhaseConfigProvider) {
   143  		if lifecycleExec.opts.HTTPProxy != "" {
   144  			provider.ctrConf.Env = append(provider.ctrConf.Env, "HTTP_PROXY="+lifecycleExec.opts.HTTPProxy)
   145  			provider.ctrConf.Env = append(provider.ctrConf.Env, "http_proxy="+lifecycleExec.opts.HTTPProxy)
   146  		}
   147  
   148  		if lifecycleExec.opts.HTTPSProxy != "" {
   149  			provider.ctrConf.Env = append(provider.ctrConf.Env, "HTTPS_PROXY="+lifecycleExec.opts.HTTPSProxy)
   150  			provider.ctrConf.Env = append(provider.ctrConf.Env, "https_proxy="+lifecycleExec.opts.HTTPSProxy)
   151  		}
   152  
   153  		if lifecycleExec.opts.NoProxy != "" {
   154  			provider.ctrConf.Env = append(provider.ctrConf.Env, "NO_PROXY="+lifecycleExec.opts.NoProxy)
   155  			provider.ctrConf.Env = append(provider.ctrConf.Env, "no_proxy="+lifecycleExec.opts.NoProxy)
   156  		}
   157  	}
   158  }
   159  
   160  func WithNetwork(networkMode string) PhaseConfigProviderOperation {
   161  	return func(provider *PhaseConfigProvider) {
   162  		provider.hostConf.NetworkMode = container.NetworkMode(networkMode)
   163  	}
   164  }
   165  
   166  func WithRegistryAccess(authConfig string) PhaseConfigProviderOperation {
   167  	return func(provider *PhaseConfigProvider) {
   168  		provider.ctrConf.Env = append(provider.ctrConf.Env, fmt.Sprintf(`CNB_REGISTRY_AUTH=%s`, authConfig))
   169  	}
   170  }
   171  
   172  func WithRoot() PhaseConfigProviderOperation {
   173  	return func(provider *PhaseConfigProvider) {
   174  		if provider.os == "windows" {
   175  			provider.ctrConf.User = windowsContainerAdmin
   176  		} else {
   177  			provider.ctrConf.User = linuxContainerAdmin
   178  		}
   179  	}
   180  }
   181  
   182  func WithContainerOperations(operations ...ContainerOperation) PhaseConfigProviderOperation {
   183  	return func(provider *PhaseConfigProvider) {
   184  		provider.containerOps = append(provider.containerOps, operations...)
   185  	}
   186  }