2424
2525package com .gpuopenanalytics .jenkins .remotedocker ;
2626
27+ import com .cloudbees .plugins .credentials .common .UsernamePasswordCredentials ;
2728import com .google .common .collect .ImmutableList ;
2829import com .gpuopenanalytics .jenkins .remotedocker .job .DockerConfiguration ;
2930import com .gpuopenanalytics .jenkins .remotedocker .job .SideDockerConfiguration ;
3435import hudson .slaves .WorkspaceList ;
3536import hudson .util .ArgumentListBuilder ;
3637import jenkins .model .Jenkins ;
38+ import org .apache .commons .lang .StringUtils ;
3739
3840import java .io .ByteArrayOutputStream ;
3941import java .io .IOException ;
@@ -58,17 +60,20 @@ public class DockerState implements Serializable {
5860 private ImmutableList <String > containerIds ;
5961 private String networkId ;
6062 private boolean removeContainers ;
63+ private FilePath loginTempDir ;
6164
6265 public DockerState (boolean debug ,
6366 String mainContainerId ,
6467 Collection <String > containerIds ,
6568 Optional <DockerNetwork > network ,
66- boolean removeContainers ) {
69+ boolean removeContainers ,
70+ FilePath loginTempDir ) {
6771 this .debug = debug ;
6872 this .mainContainerId = mainContainerId ;
6973 this .containerIds = ImmutableList .copyOf (containerIds );
7074 this .networkId = network .map (DockerNetwork ::getId ).orElse (null );
7175 this .removeContainers = removeContainers ;
76+ this .loginTempDir = loginTempDir ;
7277 }
7378
7479 private int execute (Launcher launcher ,
@@ -84,13 +89,13 @@ private int execute(Launcher launcher,
8489 return status ;
8590 }
8691
87- public void tearDown (Launcher launcher ) throws IOException , InterruptedException {
92+ public void tearDown (AbstractDockerLauncher launcher ) throws IOException , InterruptedException {
8893 if (removeContainers ) {
8994 TaskListener listener = launcher .getListener ();
9095 for (String containerId : containerIds ) {
9196 ArgumentListBuilder args = new ArgumentListBuilder ()
9297 .add ("docker" , "rm" , "-f" , containerId );
93- int status = execute (launcher , args );
98+ int status = execute (launcher . getInner () , args );
9499 if (status != 0 ) {
95100 listener .error ("Failed to remove container %s" ,
96101 containerId );
@@ -99,12 +104,69 @@ public void tearDown(Launcher launcher) throws IOException, InterruptedException
99104 if (networkId != null ) {
100105 ArgumentListBuilder args = new ArgumentListBuilder ()
101106 .add ("docker" , "network" , "rm" , networkId );
102- int status = execute (launcher , args );
107+ int status = execute (launcher . getInner () , args );
103108 if (status != 0 ) {
104109 listener .error ("Failed to remove network %s" , networkId );
105110 }
106111 }
107112 }
113+ logout (launcher .getInner ());
114+ }
115+
116+ private void logout (Launcher launcher ) throws IOException , InterruptedException {
117+ if (loginTempDir != null ) {
118+ ArgumentListBuilder args = new ArgumentListBuilder ("env" ,
119+ "HOME=" + loginTempDir
120+ .getRemote (),
121+ "docker" ,
122+ "logout" );
123+ int status = execute (launcher , args );
124+ if (status != 0 ) {
125+ launcher .getListener ().error ("Failed to docker logout" );
126+ }
127+ }
128+ }
129+
130+ /**
131+ * Attempt to <code>docker login</code>. Returns the temporary directory to
132+ * use for <code>HOME</code> to store docker credentials.
133+ *
134+ * @param buildWrapper
135+ * @param launcher
136+ * @param workspace
137+ * @return
138+ * @throws IOException
139+ * @throws InterruptedException
140+ */
141+ private static FilePath login (RemoteDockerBuildWrapper buildWrapper ,
142+ AbstractDockerLauncher launcher ,
143+ FilePath workspace ) throws IOException , InterruptedException {
144+ if (buildWrapper .getCredentialsId () != null ) {
145+ UsernamePasswordCredentials creds = buildWrapper .getCredentials ();
146+ FilePath tempDir = WorkspaceList .tempDir (workspace );
147+ launcher .configureTempDir (tempDir );
148+ ArgumentListBuilder args = new ArgumentListBuilder ("docker" ,
149+ "login" );
150+ args .add ("-u" , creds .getUsername ());
151+ args .add ("-p" );
152+ args .addMasked (creds .getPassword ());
153+ if (!StringUtils .isEmpty (buildWrapper .getDockerRegistryUrl ())) {
154+ args .add (buildWrapper .getDockerRegistryUrl ());
155+ }
156+ Launcher .ProcStarter cmd = launcher .executeCommand (args );
157+ ByteArrayOutputStream baos = new ByteArrayOutputStream ();
158+ cmd .stdout (launcher .getListener ());
159+ cmd .stderr (baos );
160+ int status = cmd .join ();
161+ if (status != 0 ) {
162+ launcher .getListener ().error ("Failed to docker login" );
163+ launcher .getListener ().error (baos .toString ());
164+ throw new RuntimeException (
165+ "Could not docker login. Are your credentials correct?" );
166+ }
167+ return tempDir ;
168+ }
169+ return null ;
108170 }
109171
110172 /**
@@ -116,6 +178,8 @@ public void tearDown(Launcher launcher) throws IOException, InterruptedException
116178 public static DockerState launchContainers (RemoteDockerBuildWrapper buildWrapper ,
117179 AbstractDockerLauncher launcher ,
118180 FilePath workspace ) throws IOException , InterruptedException {
181+ FilePath loginTempDir = login (buildWrapper , launcher , workspace );
182+
119183 Optional <DockerNetwork > network = Optional .empty ();
120184 if (!buildWrapper .getSideDockerConfigurations ().isEmpty ()) {
121185 //There are side container, so create a network
@@ -124,22 +188,25 @@ public static DockerState launchContainers(RemoteDockerBuildWrapper buildWrapper
124188 List <String > containerIds = new ArrayList <>();
125189 //Launch side containers first
126190 for (SideDockerConfiguration side : buildWrapper .getSideDockerConfigurations ()) {
127- String id = launchContainer (buildWrapper , side , false , launcher , workspace ,
191+ String id = launchContainer (buildWrapper , side , false , launcher ,
192+ workspace ,
128193 network );
129194 containerIds .add (id );
130195 }
131196
132197 //Launch main container
133198 DockerConfiguration main = buildWrapper .getDockerConfiguration ();
134- String mainId = launchContainer (buildWrapper , main , true , launcher , workspace ,
199+ String mainId = launchContainer (buildWrapper , main , true , launcher ,
200+ workspace ,
135201 network );
136202 containerIds .add (mainId );
137203 Collections .reverse (containerIds );
138204
139205 DockerState dockerState = new DockerState (buildWrapper .isDebug (),
140206 mainId , containerIds ,
141207 network ,
142- buildWrapper .isRemoveContainers ());
208+ buildWrapper .isRemoveContainers (),
209+ loginTempDir );
143210 launcher .configure (dockerState );
144211 return dockerState ;
145212 }
@@ -159,8 +226,8 @@ private static ArgumentListBuilder getlaunchArgs(RemoteDockerBuildWrapper buildW
159226 Optional <DockerNetwork > network ) throws IOException , InterruptedException {
160227 String workspacePath = workspace .getRemote ();
161228 String workspaceTarget = Optional .ofNullable (
162- buildWrapper .getWorkspaceOverride ())
163- .orElse (workspacePath );
229+ buildWrapper .getWorkspaceOverride ())
230+ .orElse (workspacePath );
164231 //Fully resolve the source workspace
165232 String workspaceSrc = Paths .get (workspacePath )
166233 .toAbsolutePath ()
@@ -212,7 +279,8 @@ private static String launchContainer(RemoteDockerBuildWrapper buildWrapper,
212279 AbstractDockerLauncher launcher ,
213280 FilePath workspace ,
214281 Optional <DockerNetwork > network ) throws IOException , InterruptedException {
215- ArgumentListBuilder args = getlaunchArgs (buildWrapper , config , isMain , launcher ,
282+ ArgumentListBuilder args = getlaunchArgs (buildWrapper , config , isMain ,
283+ launcher ,
216284 workspace , network );
217285 ByteArrayOutputStream baos = new ByteArrayOutputStream ();
218286 int status = launcher .executeCommand (args )
@@ -231,7 +299,8 @@ private static String launchContainer(RemoteDockerBuildWrapper buildWrapper,
231299 containerId ,
232300 ImmutableList .of (containerId ),
233301 Optional .empty (),
234- false );
302+ false ,
303+ null );
235304 launcher .configure (tempState );
236305 config .postCreate (launcher );
237306 return containerId ;
@@ -258,4 +327,7 @@ public Optional<String> getNetworkId() {
258327 return Optional .ofNullable (networkId );
259328 }
260329
330+ public FilePath getLoginTempDir () {
331+ return loginTempDir ;
332+ }
261333}
0 commit comments