3232import java .io .FileOutputStream ;
3333import java .io .IOException ;
3434import java .io .OutputStream ;
35+ import java .io .StringWriter ;
3536import java .nio .file .Files ;
3637import java .nio .file .Path ;
3738import java .util .ArrayList ;
@@ -61,17 +62,18 @@ public class CcmBridge implements AutoCloseable {
6162
6263 private static final Logger LOG = LoggerFactory .getLogger (CcmBridge .class );
6364
64- public static final Version VERSION =
65- Objects .requireNonNull (Version .parse (System .getProperty ("ccm.version" , "4.0.0" )));
65+ public static final Boolean SCYLLA_ENABLEMENT = Boolean .getBoolean ("ccm.scylla" );
66+
67+ public static final String CCM_VERSION_PROPERTY = System .getProperty ("ccm.version" , "4.0.0" );
68+
69+ public static final Version VERSION = Objects .requireNonNull (parseCcmVersion ());
6670
6771 public static final String INSTALL_DIRECTORY = System .getProperty ("ccm.directory" );
6872
6973 public static final String BRANCH = System .getProperty ("ccm.branch" );
7074
7175 public static final Boolean DSE_ENABLEMENT = Boolean .getBoolean ("ccm.dse" );
7276
73- public static final Boolean SCYLLA_ENABLEMENT = Boolean .getBoolean ("ccm.scylla" );
74-
7577 public static final Boolean SCYLLA_ENTERPRISE =
7678 String .valueOf (VERSION .getMajor ()).matches ("\\ d{4}" );
7779
@@ -232,6 +234,45 @@ private static boolean isWindows() {
232234 return System .getProperty ("os.name" , "" ).toLowerCase (Locale .US ).contains ("win" );
233235 }
234236
237+ private static Version parseCcmVersion () {
238+ String versionString = CCM_VERSION_PROPERTY ;
239+ Version result = null ;
240+ try {
241+ result = Version .parse (versionString );
242+ return result ;
243+ } catch (IllegalArgumentException ex ) {
244+ LOG .warn (
245+ "Failed to parse ccm.version property \' {}\' as Version instance. Attempting to fetch it through \' ccm node versionfrombuild\' " ,
246+ versionString );
247+ }
248+ Path configDir = null ;
249+ try {
250+ configDir = Files .createTempDirectory ("ccmParseVer" );
251+ configDir .toFile ().deleteOnExit ();
252+ execute (
253+ CommandLine .parse (
254+ String .format (
255+ "ccm create get_version -n 1 %s --version %s --config-dir=%s" ,
256+ (SCYLLA_ENABLEMENT ? "--scylla" : " " ), versionString , configDir )));
257+ String output =
258+ execute (
259+ CommandLine .parse (
260+ String .format ("ccm node1 versionfrombuild --config-dir=%s" , configDir )));
261+ result = Version .parse (output .trim ());
262+ LOG .info ("Cluster reports that {} corresponds to version {}" , versionString , result );
263+ } catch (IOException e ) {
264+ throw new RuntimeException (e );
265+ } finally {
266+ try {
267+ if (configDir != null ) {
268+ execute (CommandLine .parse ("ccm remove get_version --config-dir=" + configDir ));
269+ }
270+ } catch (Exception ignored ) {
271+ }
272+ }
273+ return result ;
274+ }
275+
235276 public Optional <Version > getScyllaVersion () {
236277 return SCYLLA_ENABLEMENT ? Optional .of (VERSION ) : Optional .empty ();
237278 }
@@ -264,7 +305,15 @@ public Version getCassandraVersion() {
264305 }
265306 }
266307
267- private String getCcmVersionString (Version version ) {
308+ private String getCcmVersionString (String propertyString ) {
309+ Version version = null ;
310+ try {
311+ version = Version .parse (propertyString );
312+ } catch (IllegalArgumentException ex ) {
313+ // In case it's not a recognized version pattern, use raw string.
314+ // If parseCcmVersion has not failed execution it should be usable.
315+ return propertyString ;
316+ }
268317 if (SCYLLA_ENABLEMENT ) {
269318 // Scylla OSS versions before 5.1 had RC versioning scheme of 5.0.rc3.
270319 // Scylla OSS versions after (and including 5.1) have RC versioning of 5.1.0-rc3.
@@ -307,7 +356,7 @@ public void create() {
307356 createOptions .add ("-v git:" + BRANCH .trim ().replaceAll ("\" " , "" ));
308357
309358 } else {
310- createOptions .add ("-v " + getCcmVersionString (VERSION ));
359+ createOptions .add ("-v " + getCcmVersionString (CCM_VERSION_PROPERTY ));
311360 }
312361 if (DSE_ENABLEMENT ) {
313362 createOptions .add ("--dse" );
@@ -497,21 +546,25 @@ private void executeCheckLogError() {
497546 execute (CommandLine .parse (command ));
498547 }
499548
500- private void execute (CommandLine cli ) {
501- LOG .info ("Executing: " + cli );
549+ private static String execute (CommandLine cli ) {
550+ Logger logger = CcmBridge .LOG ;
551+ logger .info ("Executing: " + cli );
502552 ExecuteWatchdog watchDog = new ExecuteWatchdog (TimeUnit .MINUTES .toMillis (10 ));
553+ StringWriter sw = new StringWriter ();
503554 try (LogOutputStream outStream =
504555 new LogOutputStream () {
505556 @ Override
506557 protected void processLine (String line , int logLevel ) {
507- LOG .info ("ccmout> {}" , line );
558+ logger .info ("ccmout> {}" , line );
559+ sw .append (line ).append (System .lineSeparator ());
508560 }
509561 };
510562 LogOutputStream errStream =
511563 new LogOutputStream () {
512564 @ Override
513565 protected void processLine (String line , int logLevel ) {
514- LOG .error ("ccmerr> {}" , line );
566+ logger .error ("ccmerr> {}" , line );
567+ sw .append (line ).append (System .lineSeparator ());
515568 }
516569 }) {
517570 Executor executor = new DefaultExecutor ();
@@ -521,7 +574,8 @@ protected void processLine(String line, int logLevel) {
521574
522575 int retValue = executor .execute (cli , ENVIRONMENT_MAP );
523576 if (retValue != 0 ) {
524- LOG .error ("Non-zero exit code ({}) returned from executing ccm command: {}" , retValue , cli );
577+ logger .error (
578+ "Non-zero exit code ({}) returned from executing ccm command: {}" , retValue , cli );
525579 }
526580 } catch (IOException ex ) {
527581 if (watchDog .killedProcess ()) {
@@ -530,6 +584,7 @@ protected void processLine(String line, int logLevel) {
530584 throw new RuntimeException ("The command '" + cli + "' failed to execute" , ex );
531585 }
532586 }
587+ return sw .toString ();
533588 }
534589
535590 @ Override
0 commit comments