3232import java .io .FileOutputStream ;
3333import java .io .IOException ;
3434import java .io .OutputStream ;
35+ import java .io .PrintWriter ;
36+ import java .io .StringWriter ;
3537import java .nio .file .Files ;
3638import java .nio .file .Path ;
3739import java .util .ArrayList ;
@@ -61,17 +63,18 @@ public class CcmBridge implements AutoCloseable {
6163
6264 private static final Logger LOG = LoggerFactory .getLogger (CcmBridge .class );
6365
64- public static final Version VERSION =
65- Objects .requireNonNull (Version .parse (System .getProperty ("ccm.version" , "4.0.0" )));
66+ public static final Boolean SCYLLA_ENABLEMENT = Boolean .getBoolean ("ccm.scylla" );
67+
68+ public static final String CCM_VERSION_PROPERTY = System .getProperty ("ccm.version" , "4.0.0" );
69+
70+ public static final Version VERSION = Objects .requireNonNull (parseCcmVersion ());
6671
6772 public static final String INSTALL_DIRECTORY = System .getProperty ("ccm.directory" );
6873
6974 public static final String BRANCH = System .getProperty ("ccm.branch" );
7075
7176 public static final Boolean DSE_ENABLEMENT = Boolean .getBoolean ("ccm.dse" );
7277
73- public static final Boolean SCYLLA_ENABLEMENT = Boolean .getBoolean ("ccm.scylla" );
74-
7578 public static final Boolean SCYLLA_ENTERPRISE =
7679 String .valueOf (VERSION .getMajor ()).matches ("\\ d{4}" );
7780
@@ -232,6 +235,45 @@ private static boolean isWindows() {
232235 return System .getProperty ("os.name" , "" ).toLowerCase (Locale .US ).contains ("win" );
233236 }
234237
238+ private static Version parseCcmVersion () {
239+ String versionString = CCM_VERSION_PROPERTY ;
240+ Version result = null ;
241+ try {
242+ result = Version .parse (versionString );
243+ return result ;
244+ } catch (IllegalArgumentException ex ) {
245+ LOG .warn (
246+ "Failed to parse ccm.version property \' {}\' as Version instance. Attempting to fetch it through \' ccm node versionfrombuild\' " ,
247+ versionString );
248+ }
249+ Path configDir = null ;
250+ try {
251+ configDir = Files .createTempDirectory ("ccmParseVer" );
252+ configDir .toFile ().deleteOnExit ();
253+ execute (
254+ CommandLine .parse (
255+ String .format (
256+ "ccm create get_version -n 1 %s --version %s --config-dir=%s" ,
257+ (SCYLLA_ENABLEMENT ? "--scylla" : " " ), versionString , configDir )));
258+ String output =
259+ execute (
260+ CommandLine .parse (
261+ String .format ("ccm node1 versionfrombuild --config-dir=%s" , configDir )));
262+ result = Version .parse (output .trim ());
263+ LOG .info ("Cluster reports that {} corresponds to version {}" , versionString , result );
264+ } catch (IOException e ) {
265+ throw new RuntimeException (e );
266+ } finally {
267+ try {
268+ if (configDir != null ) {
269+ execute (CommandLine .parse ("ccm remove get_version --config-dir=" + configDir ));
270+ }
271+ } catch (Exception ignored ) {
272+ }
273+ }
274+ return result ;
275+ }
276+
235277 public Optional <Version > getScyllaVersion () {
236278 return SCYLLA_ENABLEMENT ? Optional .of (VERSION ) : Optional .empty ();
237279 }
@@ -264,7 +306,15 @@ public Version getCassandraVersion() {
264306 }
265307 }
266308
267- private String getCcmVersionString (Version version ) {
309+ private String getCcmVersionString (String propertyString ) {
310+ Version version = null ;
311+ try {
312+ version = Version .parse (propertyString );
313+ } catch (IllegalArgumentException ex ) {
314+ // In case it's not a recognized version pattern, use raw string.
315+ // If parseCcmVersion has not failed execution it should be usable.
316+ return propertyString ;
317+ }
268318 if (SCYLLA_ENABLEMENT ) {
269319 // Scylla OSS versions before 5.1 had RC versioning scheme of 5.0.rc3.
270320 // Scylla OSS versions after (and including 5.1) have RC versioning of 5.1.0-rc3.
@@ -307,7 +357,7 @@ public void create() {
307357 createOptions .add ("-v git:" + BRANCH .trim ().replaceAll ("\" " , "" ));
308358
309359 } else {
310- createOptions .add ("-v " + getCcmVersionString (VERSION ));
360+ createOptions .add ("-v " + getCcmVersionString (CCM_VERSION_PROPERTY ));
311361 }
312362 if (DSE_ENABLEMENT ) {
313363 createOptions .add ("--dse" );
@@ -497,21 +547,26 @@ private void executeCheckLogError() {
497547 execute (CommandLine .parse (command ));
498548 }
499549
500- private void execute (CommandLine cli ) {
501- LOG .info ("Executing: " + cli );
550+ private static String execute (CommandLine cli ) {
551+ Logger logger = CcmBridge .LOG ;
552+ logger .info ("Executing: " + cli );
502553 ExecuteWatchdog watchDog = new ExecuteWatchdog (TimeUnit .MINUTES .toMillis (10 ));
554+ StringWriter sw = new StringWriter ();
555+ final PrintWriter pw = new PrintWriter (sw );
503556 try (LogOutputStream outStream =
504557 new LogOutputStream () {
505558 @ Override
506559 protected void processLine (String line , int logLevel ) {
507- LOG .info ("ccmout> {}" , line );
560+ logger .info ("ccmout> {}" , line );
561+ pw .println (line );
508562 }
509563 };
510564 LogOutputStream errStream =
511565 new LogOutputStream () {
512566 @ Override
513567 protected void processLine (String line , int logLevel ) {
514- LOG .error ("ccmerr> {}" , line );
568+ logger .error ("ccmerr> {}" , line );
569+ pw .println (line );
515570 }
516571 }) {
517572 Executor executor = new DefaultExecutor ();
@@ -521,15 +576,19 @@ protected void processLine(String line, int logLevel) {
521576
522577 int retValue = executor .execute (cli , ENVIRONMENT_MAP );
523578 if (retValue != 0 ) {
524- LOG .error ("Non-zero exit code ({}) returned from executing ccm command: {}" , retValue , cli );
579+ logger .error (
580+ "Non-zero exit code ({}) returned from executing ccm command: {}" , retValue , cli );
525581 }
526582 } catch (IOException ex ) {
527583 if (watchDog .killedProcess ()) {
528584 throw new RuntimeException ("The command '" + cli + "' was killed after 10 minutes" );
529585 } else {
530586 throw new RuntimeException ("The command '" + cli + "' failed to execute" , ex );
531587 }
588+ } finally {
589+ pw .close ();
532590 }
591+ return sw .toString ();
533592 }
534593
535594 @ Override
0 commit comments