2222
2323import java .io .IOException ;
2424import java .io .OutputStream ;
25+ import java .net .URI ;
2526import java .nio .file .Paths ;
27+ import java .util .HashMap ;
2628import java .util .ArrayList ;
2729import java .util .List ;
2830import java .util .Map ;
2931import java .util .function .BiConsumer ;
3032
33+ import com .google .common .collect .ImmutableMap ;
3134import com .spotify .docker .client .DefaultDockerClient ;
3235import com .spotify .docker .client .DockerCertificates ;
3336import com .spotify .docker .client .DockerClient ;
3437import com .spotify .docker .client .DockerClient .LogsParam ;
3538import com .spotify .docker .client .LogStream ;
3639import com .spotify .docker .client .exceptions .DockerCertificateException ;
3740import com .spotify .docker .client .exceptions .DockerException ;
38-
3941import eu .openanalytics .containerproxy .ContainerProxyException ;
4042import eu .openanalytics .containerproxy .backend .AbstractContainerBackend ;
4143import eu .openanalytics .containerproxy .model .runtime .Container ;
4244import eu .openanalytics .containerproxy .model .runtime .Proxy ;
45+ import eu .openanalytics .containerproxy .model .runtime .runtimevalues .InstanceIdKey ;
46+ import eu .openanalytics .containerproxy .model .runtime .runtimevalues .RuntimeValue ;
47+ import eu .openanalytics .containerproxy .model .runtime .runtimevalues .RuntimeValueKey ;
48+ import eu .openanalytics .containerproxy .model .runtime .runtimevalues .RuntimeValueKeyRegistry ;
4349import eu .openanalytics .containerproxy .util .PortAllocator ;
4450
51+ import java .io .IOException ;
52+ import java .io .OutputStream ;
53+ import java .net .URI ;
54+ import java .nio .file .Paths ;
55+ import java .util .ArrayList ;
56+ import java .util .List ;
57+ import java .util .Map ;
58+ import java .util .Optional ;
59+ import java .util .function .BiConsumer ;
60+
4561
4662public abstract class AbstractDockerBackend extends AbstractContainerBackend {
47-
63+
4864 private static final String PROPERTY_PREFIX = "proxy.docker." ;
4965
5066 protected static final String PROPERTY_APP_PORT = "port" ;
5167 protected static final String PROPERTY_PORT_RANGE_START = "port-range-start" ;
5268 protected static final String PROPERTY_PORT_RANGE_MAX = "port-range-max" ;
53-
69+
5470 protected static final String DEFAULT_TARGET_URL = DEFAULT_TARGET_PROTOCOL + "://localhost" ;
55-
71+
5672 protected PortAllocator portAllocator ;
5773 protected DockerClient dockerClient ;
58-
74+
5975 @ Override
6076 public void initialize () throws ContainerProxyException {
6177 super .initialize ();
62-
78+
6379 int startPort = Integer .valueOf (getProperty (PROPERTY_PORT_RANGE_START , "20000" ));
6480 int maxPort = Integer .valueOf (getProperty (PROPERTY_PORT_RANGE_MAX , "-1" ));
6581 portAllocator = new PortAllocator (startPort , maxPort );
66-
82+
6783 DefaultDockerClient .Builder builder = null ;
6884 try {
6985 builder = DefaultDockerClient .fromEnv ();
@@ -73,7 +89,7 @@ public void initialize() throws ContainerProxyException {
7389
7490 String confCertPath = getProperty (PROPERTY_CERT_PATH );
7591 if (confCertPath != null ) {
76- try {
92+ try {
7793 builder .dockerCertificates (DockerCertificates .builder ().dockerCertPath (Paths .get (confCertPath )).build ().orNull ());
7894 } catch (DockerCertificateException e ) {
7995 throw new ContainerProxyException ("Failed to initialize docker client using certificates from " + confCertPath , e );
@@ -85,12 +101,12 @@ public void initialize() throws ContainerProxyException {
85101
86102 dockerClient = builder .build ();
87103 }
88-
104+
89105 @ Override
90106 public BiConsumer <OutputStream , OutputStream > getOutputAttacher (Proxy proxy ) {
91107 Container c = getPrimaryContainer (proxy );
92108 if (c == null ) return null ;
93-
109+
94110 return (stdOut , stdErr ) -> {
95111 try {
96112 LogStream logStream = dockerClient .logs (c .getId (), LogsParam .follow (), LogsParam .stdout (), LogsParam .stderr ());
@@ -105,11 +121,29 @@ public BiConsumer<OutputStream, OutputStream> getOutputAttacher(Proxy proxy) {
105121 protected String getPropertyPrefix () {
106122 return PROPERTY_PREFIX ;
107123 }
108-
124+
109125 protected Container getPrimaryContainer (Proxy proxy ) {
110126 return proxy .getContainers ().isEmpty () ? null : proxy .getContainers ().get (0 );
111127 }
112128
129+ abstract protected URI calculateTarget (Container container , int containerPort , int hostPort ) throws Exception ;
130+
131+ public void setupPortMappingExistingProxy (Proxy proxy , Container container , Map <Integer , Integer > portBindings ) throws Exception {
132+ for (String mappingKey : container .getSpec ().getPortMapping ().keySet ()) {
133+ int containerPort = container .getSpec ().getPortMapping ().get (mappingKey );
134+
135+ int servicePort = -1 ; // in case of internal networking
136+ if (portBindings .containsKey (containerPort ) && portBindings .get (containerPort ) != 0 ) {
137+ // in case of non internal networking
138+ servicePort = portBindings .get (containerPort );
139+ portAllocator .addExistingPort (proxy .getUserId (), servicePort );
140+ }
141+
142+ String mapping = mappingStrategy .createMapping (mappingKey , container , proxy );
143+ URI target = calculateTarget (container , containerPort , servicePort );
144+ proxy .getTargets ().put (mapping , target );
145+ }
146+ }
113147
114148 protected List <String > convertEnv (Map <String , String > env ) {
115149 List <String > res = new ArrayList <>();
@@ -121,4 +155,33 @@ protected List<String> convertEnv(Map<String, String> env) {
121155 return res ;
122156 }
123157
158+ protected Map <RuntimeValueKey , RuntimeValue > parseLabelsAsRuntimeValues (String containerId , ImmutableMap <String , String > labels ) {
159+ if (labels == null ) {
160+ return null ;
161+ }
162+
163+ String containerInstanceId = labels .get (InstanceIdKey .inst .getKeyAsLabel ());
164+ if (containerInstanceId == null || !containerInstanceId .equals (instanceId )) {
165+ log .warn ("Ignoring container {} because instanceId {} is not correct" , containerId , containerInstanceId );
166+ return null ;
167+ }
168+
169+ Map <RuntimeValueKey , RuntimeValue > runtimeValues = new HashMap <>();
170+
171+ for (RuntimeValueKey key : RuntimeValueKeyRegistry .getRuntimeValueKeys ()) {
172+ if (key .getIncludeAsLabel () || key .getIncludeAsAnnotation ()) {
173+ String value = labels .get (key .getKeyAsLabel ());
174+ if (value != null ) {
175+ runtimeValues .put (key , new RuntimeValue (key , value ));
176+ } else if (key .isRequired ()) {
177+ // value is null but is required
178+ log .warn ("Ignoring container {} because no label named {} is found" , containerId , key .getKeyAsLabel ());
179+ return null ;
180+ }
181+ }
182+ }
183+
184+ return runtimeValues ;
185+ }
186+
124187}
0 commit comments