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 }