44package com .oracle .weblogic .imagetool .cli .menu ;
55
66import java .io .File ;
7- import java .io .FileInputStream ;
87import java .io .IOException ;
98import java .nio .file .Files ;
109import java .nio .file .Path ;
1110import java .nio .file .Paths ;
1211import java .util .ArrayList ;
13- import java .util .Arrays ;
1412import java .util .Collections ;
1513import java .util .LinkedList ;
1614import java .util .List ;
17- import java .util .Properties ;
1815import java .util .concurrent .Callable ;
1916import java .util .regex .Matcher ;
2017import java .util .regex .Pattern ;
3835import com .oracle .weblogic .imagetool .util .DockerfileOptions ;
3936import com .oracle .weblogic .imagetool .util .HttpUtil ;
4037import com .oracle .weblogic .imagetool .util .Utils ;
38+ import com .oracle .weblogic .imagetool .util .ValidationResult ;
4139import picocli .CommandLine .Option ;
4240import picocli .CommandLine .Unmatched ;
4341
4442public abstract class ImageOperation implements Callable <CommandResponse > {
4543
4644 private static final LoggingFacade logger = LoggingFactory .getLogger (ImageOperation .class );
4745 // DockerfileOptions provides switches and values to the customize the Dockerfile template
48- protected DockerfileOptions dockerfileOptions ;
46+ DockerfileOptions dockerfileOptions ;
4947 protected CacheStore cacheStore = new CacheStoreFactory ().get ();
5048 private String nonProxyHosts = null ;
49+ private String tempDirectory = null ;
5150 boolean isCliMode ;
5251 String password ;
5352
@@ -89,43 +88,80 @@ private String handlePasswordOptions() throws IOException {
8988 return Utils .getPasswordFromInputs (passwordStr , passwordFile , passwordEnv );
9089 }
9190
91+ /**
92+ * Return the WLS installer type for this operation.
93+ * @return WLS, FMW, or RestrictedJRF
94+ */
95+ public abstract WLSInstallerType getInstallerType ();
96+
97+ /**
98+ * Return the WLS installer version string.
99+ * @return something like 12.2.1.3.0
100+ */
101+ public abstract String getInstallerVersion ();
102+
103+ /**
104+ * Returns true if any patches should be applied.
105+ * A PSU is considered a patch.
106+ * @return true if applying patches
107+ */
108+ boolean applyingPatches () {
109+ return latestPSU || !patches .isEmpty ();
110+ }
111+
92112 /**
93113 * Builds a list of build args to pass on to docker with the required patches.
94114 * Also, creates links to patches directory under build context instead of copying over.
95115 *
96- * @param tmpDir build context dir
97- * @param tmpPatchesDir patches dir under build context
98116 * @return list of strings
99117 * @throws Exception in case of error
100118 */
101- List <String > handlePatchFiles (String tmpDir , Path tmpPatchesDir ) throws Exception {
119+ List <String > handlePatchFiles (String previousInventory ) throws Exception {
102120 logger .entering ();
103121 List <String > retVal = new LinkedList <>();
122+
123+ if (!applyingPatches ()) {
124+ return retVal ;
125+ }
126+
127+ String toPatchesPath = createPatchesTempDirectory ().toAbsolutePath ().toString ();
128+
104129 List <String > patchLocations = new LinkedList <>();
105- String toPatchesPath = tmpPatchesDir .toAbsolutePath ().toString ();
130+
131+ List <String > patchList = new ArrayList <>(patches );
106132
107133 if (latestPSU ) {
108134 if (userId == null || password == null ) {
109- throw new Exception ("No credentials provided. Cannot determine "
110- + "latestPSU" );
111- } else {
112- String patchId = ARUUtil .getLatestPSUNumber (installerType .toString (), installerVersion ,
113- userId ,
114- password );
115- if (Utils .isEmptyString (patchId )) {
116- throw new Exception (String .format ("Failed to find latest psu for product category %s, version %s" ,
117- installerType .toString (), installerVersion ));
118- }
119- logger .finest ("Found latest PSU " + patchId );
120- FileResolver psuResolver = new PatchFile (useCache , installerType .toString (), installerVersion ,
121- patchId , userId , password );
122- patchLocations .add (psuResolver .resolve (cacheStore ));
135+ throw new Exception ("No credentials provided. Cannot determine latestPSU" );
123136 }
124137
138+ // PSUs for WLS and JRF installers are considered WLS patches
139+ String patchId = ARUUtil .getLatestPSUNumber (WLSInstallerType .WLS , getInstallerVersion (), userId , password );
140+ if (Utils .isEmptyString (patchId )) {
141+ throw new Exception (String .format ("Failed to find latest psu for product category %s, version %s" ,
142+ getInstallerType (), getInstallerVersion ()));
143+ }
144+ logger .fine ("Found latest PSU {0}" , patchId );
145+ FileResolver psuResolver = new PatchFile (useCache , getInstallerType ().toString (), getInstallerVersion (),
146+ patchId , userId , password );
147+ patchLocations .add (psuResolver .resolve (cacheStore ));
148+ // Add PSU patch ID to the patchList for validation (conflict check)
149+ patchList .add (patchId );
125150 }
151+
152+ logger .info ("IMG-0012" );
153+ ValidationResult validationResult = ARUUtil .validatePatches (previousInventory , patchList , userId , password );
154+ if (validationResult .isSuccess ()) {
155+ logger .info ("IMG-0006" );
156+ } else {
157+ String error = validationResult .getErrorMessage ();
158+ logger .severe (error );
159+ throw new IllegalArgumentException (error );
160+ }
161+
126162 if (patches != null && !patches .isEmpty ()) {
127163 for (String patchId : patches ) {
128- patchLocations .add (new PatchFile (useCache , installerType .toString (), installerVersion ,
164+ patchLocations .add (new PatchFile (useCache , getInstallerType () .toString (), getInstallerVersion () ,
129165 patchId , userId , password ).resolve (cacheStore ));
130166 }
131167 }
@@ -181,14 +217,16 @@ List<String> getInitialBuildCmd() {
181217 }
182218
183219 public String getTempDirectory () throws IOException {
184- Path tmpDir = Files .createTempDirectory (Paths .get (Utils .getBuildWorkingDir ()), "wlsimgbuilder_temp" );
185- String pathAsString = tmpDir .toAbsolutePath ().toString ();
186- logger .info ("IMG-0003" , pathAsString );
187- return pathAsString ;
220+ if (tempDirectory == null ) {
221+ Path tmpDir = Files .createTempDirectory (Paths .get (Utils .getBuildWorkingDir ()), "wlsimgbuilder_temp" );
222+ tempDirectory = tmpDir .toAbsolutePath ().toString ();
223+ logger .info ("IMG-0003" , tempDirectory );
224+ }
225+ return tempDirectory ;
188226 }
189227
190- public Path createPatchesTempDirectory (String tmpDir ) throws IOException {
191- Path tmpPatchesDir = Files .createDirectory (Paths .get (tmpDir , "patches" ));
228+ public Path createPatchesTempDirectory () throws IOException {
229+ Path tmpPatchesDir = Files .createDirectory (Paths .get (getTempDirectory () , "patches" ));
192230 Files .createFile (Paths .get (tmpPatchesDir .toAbsolutePath ().toString (), "dummy.txt" ));
193231 return tmpPatchesDir ;
194232 }
@@ -242,7 +280,7 @@ private void handleChown() {
242280 * @return list of build argument parameters for docker build
243281 * @throws Exception in case of error
244282 */
245- protected List <String > handleInstallerFiles (String tmpDir ) throws Exception {
283+ List <String > handleInstallerFiles (String tmpDir ) throws Exception {
246284
247285 logger .entering (tmpDir );
248286 List <String > retVal = new LinkedList <>();
@@ -282,31 +320,6 @@ protected List<InstallerFile> gatherRequiredInstallers() throws Exception {
282320 return result ;
283321 }
284322
285-
286- /**
287- * Certain environment variables need to be set in docker images for WDT domains to work.
288- *
289- * @param wdtVariablesPath wdt variables file path.
290- * @return list of build args
291- * @throws IOException in case of error
292- */
293- private List <String > getWdtRequiredBuildArgs (Path wdtVariablesPath ) throws IOException {
294- logger .finer ("Entering CreateImage.getWdtRequiredBuildArgs: " + wdtVariablesPath .toAbsolutePath ().toString ());
295- List <String > retVal = new LinkedList <>();
296- Properties variableProps = new Properties ();
297- variableProps .load (new FileInputStream (wdtVariablesPath .toFile ()));
298- List <Object > matchingKeys = variableProps .keySet ().stream ().filter (
299- x -> variableProps .getProperty (((String ) x )) != null
300- && Constants .REQD_WDT_BUILD_ARGS .contains (((String ) x ).toUpperCase ())
301- ).collect (Collectors .toList ());
302- matchingKeys .forEach (x -> {
303- retVal .add (Constants .BUILD_ARG );
304- retVal .add (((String ) x ).toUpperCase () + "=" + variableProps .getProperty ((String ) x ));
305- });
306- logger .finer ("Exiting CreateImage.getWdtRequiredBuildArgs: " );
307- return retVal ;
308- }
309-
310323 /**
311324 * Checks whether the user requested a domain to be created with WDT.
312325 * If so, returns the required build args to pass to docker and creates required file links to pass
@@ -316,7 +329,7 @@ private List<String> getWdtRequiredBuildArgs(Path wdtVariablesPath) throws IOExc
316329 * @return list of build args
317330 * @throws IOException in case of error
318331 */
319- protected List <String > handleWdtArgsIfRequired (String tmpDir ) throws IOException {
332+ List <String > handleWdtArgsIfRequired (String tmpDir ) throws IOException {
320333 logger .entering (tmpDir );
321334
322335 List <String > retVal = new LinkedList <>();
@@ -340,7 +353,7 @@ protected List<String> handleWdtArgsIfRequired(String tmpDir) throws IOException
340353
341354 dockerfileOptions .setWdtDomainType (wdtDomainType );
342355 if (wdtDomainType != DomainType .WLS ) {
343- if (installerType != WLSInstallerType .FMW ) {
356+ if (getInstallerType () != WLSInstallerType .FMW ) {
344357 throw new IOException ("FMW installer is required for JRF domain" );
345358 }
346359 if (runRcu ) {
@@ -397,10 +410,6 @@ private void addWdtUrl(String wdtKey) throws Exception {
397410 logger .exiting ();
398411 }
399412
400- WLSInstallerType installerType = WLSInstallerType .WLS ;
401-
402- String installerVersion = Constants .DEFAULT_WLS_VERSION ;
403-
404413 @ Option (
405414 names = {"--useCache" },
406415 paramLabel = "<Cache Policy>" ,
@@ -504,6 +513,12 @@ private void addWdtUrl(String wdtKey) throws Exception {
504513 private String [] osUserAndGroup ;
505514
506515
516+ @ Option (
517+ names = {"--opatchBugNumber" },
518+ description = "the patch number for OPatch (patching OPatch)"
519+ )
520+ String opatchBugNumber = "28186730" ;
521+
507522 @ Option (
508523 names = {"--wdtModel" },
509524 description = "path to the WDT model file that defines the Domain to create"
0 commit comments