diff --git a/pom.xml b/pom.xml index c44b1ba..45b7507 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ https://sonarcloud.io com.dtsx.astra.cli.AstraCli UTF-8 - 0.3.5 + 0.3.6-SNAPSHOT 2.4.0 2.9.0 2.0.3 diff --git a/src/main/java/com/dtsx/astra/cli/AstraCli.java b/src/main/java/com/dtsx/astra/cli/AstraCli.java index bbf0f2b..813b4b1 100644 --- a/src/main/java/com/dtsx/astra/cli/AstraCli.java +++ b/src/main/java/com/dtsx/astra/cli/AstraCli.java @@ -39,10 +39,21 @@ import com.dtsx.astra.cli.db.exception.KeyspaceAlreadyExistException; import com.dtsx.astra.cli.db.keyspace.DbCreateKeyspaceCmd; import com.dtsx.astra.cli.db.keyspace.DbListKeyspacesCmd; -import com.dtsx.astra.cli.iam.*; -import com.dtsx.astra.cli.iam.exception.RoleNotFoundException; -import com.dtsx.astra.cli.iam.exception.UserAlreadyExistException; -import com.dtsx.astra.cli.iam.exception.UserNotFoundException; +import com.dtsx.astra.cli.db.region.*; +import com.dtsx.astra.cli.db.tool.DbGraphqlPlaygroundCmd; +import com.dtsx.astra.cli.db.tool.DbSwaggerUICmd; +import com.dtsx.astra.cli.iam.role.exception.RoleNotFoundException; +import com.dtsx.astra.cli.iam.user.exception.UserAlreadyExistException; +import com.dtsx.astra.cli.iam.user.exception.UserNotFoundException; +import com.dtsx.astra.cli.iam.role.RoleGetCmd; +import com.dtsx.astra.cli.iam.role.RoleListCmd; +import com.dtsx.astra.cli.iam.token.TokenCreateCmd; +import com.dtsx.astra.cli.iam.token.TokenDeleteCmd; +import com.dtsx.astra.cli.iam.token.TokenListCmd; +import com.dtsx.astra.cli.iam.user.UserDeleteCmd; +import com.dtsx.astra.cli.iam.user.UserGetCmd; +import com.dtsx.astra.cli.iam.user.UserInviteCmd; +import com.dtsx.astra.cli.iam.user.UserListCmd; import com.dtsx.astra.cli.org.*; import com.dtsx.astra.cli.streaming.*; import com.dtsx.astra.cli.streaming.cdc.StreamingCreateCdcCmd; @@ -103,14 +114,18 @@ DbListCmd.class, DbGetCmd.class, DbStatusCmd.class, // Operation DbResumeCmd.class, DbDownloadScbCmd.class, DbCreateDotEnvCmd.class, - // Keyspaces - DbCreateKeyspaceCmd.class, DbListKeyspacesCmd.class, // DsBulk DbCountCmd.class, DbLoadCmd.class, DbUnLoadCmd.class, // Cqlshell DbCqlShellCmd.class, - // List Regions - DbListRegionsClassicCmd.class, DbListRegionsServerlessCmd.class + // Work with Keyspaces + DbCreateKeyspaceCmd.class, DbListKeyspacesCmd.class, + // Work with Regions + DbCreateRegionCmd.class, DbListRegionsCmd.class, DbDeleteRegionCmd.class, + // List Region + DbListRegionsClassicCmd.class, DbListRegionsServerlessCmd.class, + // External Tools + DbSwaggerUICmd.class, DbGraphqlPlaygroundCmd.class }), @Group( @@ -124,10 +139,11 @@ StreamingListCmd.class, StreamingGetCmd.class, StreamingExistCmd.class, StreamingStatusCmd.class, StreamingPulsarTokenCmd.class, StreamingCreateDotEnvCmd.class, + // list Regions StreamingListRegionsCmd.class, // Pulsar Shell PulsarShellCmd.class, - // Create CDC + // Change Data Capture StreamingCreateCdcCmd.class, StreamingDeleteCdcCmd.class, StreamingGetCdcCmd.class }), @@ -147,6 +163,14 @@ UserGetCmd.class, UserInviteCmd.class, UserDeleteCmd.class, UserListCmd.class }), + + @Group( + name= "token", + description = "Manage tokens", + defaultCommand = TokenListCmd.class, + commands = { + TokenListCmd.class, TokenCreateCmd.class, TokenDeleteCmd.class + }) }) public class AstraCli { @@ -239,6 +263,7 @@ public static ExitCode run(Class clazz, String[] args) { AstraCliConsole.outputError(ExitCode.UNAVAILABLE, ex.getMessage()); return ExitCode.UNAVAILABLE; } catch (Exception ex) { + ex.printStackTrace(); AstraCliConsole.outputError(ExitCode.INTERNAL_ERROR, ex.getMessage()); return ExitCode.INTERNAL_ERROR; } diff --git a/src/main/java/com/dtsx/astra/cli/config/ConfigCreateCmd.java b/src/main/java/com/dtsx/astra/cli/config/ConfigCreateCmd.java index 899ddf5..b6d42b6 100644 --- a/src/main/java/com/dtsx/astra/cli/config/ConfigCreateCmd.java +++ b/src/main/java/com/dtsx/astra/cli/config/ConfigCreateCmd.java @@ -25,8 +25,8 @@ import com.dtsx.astra.cli.core.exception.InvalidTokenException; import com.dtsx.astra.cli.core.exception.TokenNotFoundException; import com.dtsx.astra.cli.core.out.AstraCliConsole; -import com.dtsx.astra.sdk.organizations.OrganizationsClient; -import com.dtsx.astra.sdk.organizations.domain.Organization; +import com.dtsx.astra.sdk.org.OrganizationsClient; +import com.dtsx.astra.sdk.org.domain.Organization; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; diff --git a/src/main/java/com/dtsx/astra/cli/config/ConfigDeleteCmd.java b/src/main/java/com/dtsx/astra/cli/config/ConfigDeleteCmd.java index 4e5d3c9..a7c5a61 100644 --- a/src/main/java/com/dtsx/astra/cli/config/ConfigDeleteCmd.java +++ b/src/main/java/com/dtsx/astra/cli/config/ConfigDeleteCmd.java @@ -46,7 +46,7 @@ public class ConfigDeleteCmd extends AbstractCmd { /** {@inheritDoc} */ @Override public void execute() { - OperationsConfig.assertSectionExist(sectionName); + ServiceConfig.assertSectionExist(sectionName); ctx().getConfiguration().deleteSection(sectionName); ctx().getConfiguration().save(); AstraCliConsole.outputSuccess("Section '" + sectionName + "' has been deleted."); diff --git a/src/main/java/com/dtsx/astra/cli/config/ConfigGetCmd.java b/src/main/java/com/dtsx/astra/cli/config/ConfigGetCmd.java index dd1f21e..b04c1c3 100644 --- a/src/main/java/com/dtsx/astra/cli/config/ConfigGetCmd.java +++ b/src/main/java/com/dtsx/astra/cli/config/ConfigGetCmd.java @@ -56,7 +56,7 @@ public class ConfigGetCmd extends AbstractCmd { /** {@inheritDoc} */ @Override public void execute() throws ConfigurationException { - OperationsConfig.assertSectionExist(sectionName); + ServiceConfig.assertSectionExist(sectionName); if (key != null) { Optional optKey = ctx().getConfiguration().getSectionKey(sectionName, key); if (optKey.isEmpty()) { diff --git a/src/main/java/com/dtsx/astra/cli/config/ConfigListCmd.java b/src/main/java/com/dtsx/astra/cli/config/ConfigListCmd.java index 60ccd36..eb88ac2 100644 --- a/src/main/java/com/dtsx/astra/cli/config/ConfigListCmd.java +++ b/src/main/java/com/dtsx/astra/cli/config/ConfigListCmd.java @@ -36,7 +36,7 @@ public class ConfigListCmd extends AbstractCmd { /** {@inheritDoc} */ @Override public void execute() { - OperationsConfig.listConfigurations(); + ServiceConfig.listConfigurations(); } } diff --git a/src/main/java/com/dtsx/astra/cli/config/ConfigUseCmd.java b/src/main/java/com/dtsx/astra/cli/config/ConfigUseCmd.java index b019f57..85e6e9d 100644 --- a/src/main/java/com/dtsx/astra/cli/config/ConfigUseCmd.java +++ b/src/main/java/com/dtsx/astra/cli/config/ConfigUseCmd.java @@ -48,7 +48,7 @@ public class ConfigUseCmd extends AbstractCmd { /** {@inheritDoc} */ @Override public void execute() { - OperationsConfig.assertSectionExist(sectionName); + ServiceConfig.assertSectionExist(sectionName); ctx().getConfiguration().copySection(sectionName, AstraConfiguration.ASTRARC_DEFAULT); ctx().getConfiguration().save(); AstraCliConsole.outputSuccess("Section '" + sectionName + "' is set as default."); diff --git a/src/main/java/com/dtsx/astra/cli/config/OperationsConfig.java b/src/main/java/com/dtsx/astra/cli/config/ServiceConfig.java similarity index 98% rename from src/main/java/com/dtsx/astra/cli/config/OperationsConfig.java rename to src/main/java/com/dtsx/astra/cli/config/ServiceConfig.java index e4d529e..1b27ac8 100644 --- a/src/main/java/com/dtsx/astra/cli/config/OperationsConfig.java +++ b/src/main/java/com/dtsx/astra/cli/config/ServiceConfig.java @@ -35,7 +35,7 @@ * * @author Cedrick LUNVEN (@clunven) */ -public class OperationsConfig { +public class ServiceConfig { /** * Title of the table. @@ -45,7 +45,7 @@ public class OperationsConfig { /** * Hide default constructor */ - private OperationsConfig() {} + private ServiceConfig() {} /** * Syntax sugar. diff --git a/src/main/java/com/dtsx/astra/cli/config/SetupCmd.java b/src/main/java/com/dtsx/astra/cli/config/SetupCmd.java index bdf45bc..34b32b7 100644 --- a/src/main/java/com/dtsx/astra/cli/config/SetupCmd.java +++ b/src/main/java/com/dtsx/astra/cli/config/SetupCmd.java @@ -24,7 +24,7 @@ import com.dtsx.astra.cli.core.exception.InvalidTokenException; import com.dtsx.astra.cli.core.out.AstraCliConsole; import com.dtsx.astra.cli.core.out.LoggerShell; -import com.dtsx.astra.sdk.organizations.OrganizationsClient; +import com.dtsx.astra.sdk.org.OrganizationsClient; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; import org.fusesource.jansi.Ansi; @@ -94,7 +94,9 @@ private void createDefaultSection(String token) ccc.sectionName = new OrganizationsClient(token).organization().getName(); ccc.run(); } catch(Exception e) { - LoggerShell.error("Token provided is invalid. Please enter a valid token or quit with CTRL+C"); + LoggerShell.warning("Invalid token: It must be start with 'AstraCS:..' and have Organization Administrator privileges."); + LoggerShell.warning("Generated token at database creation cannot be used."); + LoggerShell.warning("Please enter a valid token or quit with CTRL+C."); throw new InvalidTokenException(token, e); } } diff --git a/src/main/java/com/dtsx/astra/cli/core/CliContext.java b/src/main/java/com/dtsx/astra/cli/core/CliContext.java index b98c78f..35ab01f 100644 --- a/src/main/java/com/dtsx/astra/cli/core/CliContext.java +++ b/src/main/java/com/dtsx/astra/cli/core/CliContext.java @@ -26,8 +26,9 @@ import com.dtsx.astra.cli.core.out.AstraCliConsole; import com.dtsx.astra.cli.core.out.LoggerShell; import com.dtsx.astra.cli.core.out.OutputFormat; -import com.dtsx.astra.sdk.databases.DatabasesClient; -import com.dtsx.astra.sdk.organizations.OrganizationsClient; +import com.dtsx.astra.sdk.db.DatabasesClient; +import com.dtsx.astra.sdk.org.OrganizationsClient; +import com.dtsx.astra.sdk.org.OrganizationsClient; import com.dtsx.astra.sdk.streaming.StreamingClient; import com.dtsx.astra.sdk.utils.AstraRc; import org.apache.commons.lang3.StringUtils; @@ -183,7 +184,7 @@ private void validateToken() { */ public String getToken() throws TokenNotFoundException { - if (StringUtils.isEmpty(tokenOptions.token())) { + if (tokenOptions == null || StringUtils.isEmpty(tokenOptions.token())) { throw new TokenNotFoundException(); } return tokenOptions.token(); diff --git a/src/main/java/com/dtsx/astra/cli/core/exception/TokenNotFoundException.java b/src/main/java/com/dtsx/astra/cli/core/exception/TokenNotFoundException.java index a4217e7..c6d20f6 100644 --- a/src/main/java/com/dtsx/astra/cli/core/exception/TokenNotFoundException.java +++ b/src/main/java/com/dtsx/astra/cli/core/exception/TokenNotFoundException.java @@ -40,4 +40,11 @@ public TokenNotFoundException() { super("Token has not been found."); } + /** + * Default constructor + */ + public TokenNotFoundException(String tokenId) { + super("Token "+ tokenId + " has not been found."); + } + } diff --git a/src/main/java/com/dtsx/astra/cli/db/AbstractDatabaseCmd.java b/src/main/java/com/dtsx/astra/cli/db/AbstractDatabaseCmd.java index ab1dc97..77f896f 100644 --- a/src/main/java/com/dtsx/astra/cli/db/AbstractDatabaseCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/AbstractDatabaseCmd.java @@ -32,7 +32,7 @@ public abstract class AbstractDatabaseCmd extends AbstractConnectedCmd { /** Access to sdb Services. */ - protected DatabaseService dbServices = DatabaseService.getInstance(); + protected ServiceDatabase dbServices = ServiceDatabase.getInstance(); /** * Database name or identifier diff --git a/src/main/java/com/dtsx/astra/cli/db/DatabaseDao.java b/src/main/java/com/dtsx/astra/cli/db/DaoDatabase.java similarity index 94% rename from src/main/java/com/dtsx/astra/cli/db/DatabaseDao.java rename to src/main/java/com/dtsx/astra/cli/db/DaoDatabase.java index 8278885..7144994 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DatabaseDao.java +++ b/src/main/java/com/dtsx/astra/cli/db/DaoDatabase.java @@ -27,10 +27,10 @@ import com.dtsx.astra.cli.db.exception.DatabaseNotFoundException; import com.dtsx.astra.cli.utils.AstraCliUtils; import com.dtsx.astra.cli.utils.FileUtils; -import com.dtsx.astra.sdk.databases.DatabaseClient; -import com.dtsx.astra.sdk.databases.DatabasesClient; -import com.dtsx.astra.sdk.databases.domain.Database; -import com.dtsx.astra.sdk.databases.domain.Datacenter; +import com.dtsx.astra.sdk.db.DatabaseClient; +import com.dtsx.astra.sdk.db.DatabasesClient; +import com.dtsx.astra.sdk.db.domain.Database; +import com.dtsx.astra.sdk.db.domain.Datacenter; import java.io.File; import java.util.List; @@ -42,12 +42,12 @@ * * @author Cedrick LUNVEN (@clunven) */ -public class DatabaseDao { +public class DaoDatabase { /** * Singleton Pattern */ - private static DatabaseDao instance; + private static DaoDatabase instance; /** * Singleton Pattern. @@ -55,9 +55,9 @@ public class DatabaseDao { * @return * instance of the service. */ - public static synchronized DatabaseDao getInstance() { + public static synchronized DaoDatabase getInstance() { if (null == instance) { - instance = new DatabaseDao(); + instance = new DaoDatabase(); } return instance; } @@ -65,7 +65,7 @@ public static synchronized DatabaseDao getInstance() { /** * Default Constructor. */ - private DatabaseDao() { + private DaoDatabase() { } diff --git a/src/main/java/com/dtsx/astra/cli/db/DbCreateCmd.java b/src/main/java/com/dtsx/astra/cli/db/DbCreateCmd.java index dc8bb6c..a2aaa50 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbCreateCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/DbCreateCmd.java @@ -26,7 +26,7 @@ import com.dtsx.astra.cli.db.exception.DatabaseNotFoundException; import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; import com.dtsx.astra.cli.db.exception.KeyspaceAlreadyExistException; -import com.dtsx.astra.sdk.databases.domain.DatabaseStatusType; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; @@ -52,7 +52,7 @@ public class DbCreateCmd extends AbstractDatabaseCmd { */ @Option(name = { "-r", "--region" }, title = "DB_REGION", arity = 1, description = "Cloud provider region to provision") - protected String region = DatabaseService.DEFAULT_REGION; + protected String region = ServiceDatabase.DEFAULT_REGION; /** * Default keyspace created with the Db @@ -66,14 +66,20 @@ public class DbCreateCmd extends AbstractDatabaseCmd { */ @Option(name = { "--wait" }, description = "Will wait until the database become ACTIVE") - protected boolean wait = false; + protected boolean wait = true; + + /** + * Will not wait for the database become available. + */ + @Option(name = { "--async" }, description = "Will not wait for the resource to become available") + protected boolean async = false; /** * Provide a limit to the wait period in seconds, default is 180s. */ @Option(name = { "--timeout" }, description = "Provide a limit to the wait period in seconds, default is 300s.") - protected int timeout = DatabaseService.DEFAULT_TIMEOUT_SECONDS; + protected int timeout = ServiceDatabase.DEFAULT_TIMEOUT_SECONDS; /** {@inheritDoc} */ @Override @@ -81,7 +87,7 @@ public void execute() throws DatabaseNameNotUniqueException, DatabaseNotFoundException, InvalidDatabaseStateException, InvalidArgumentException, KeyspaceAlreadyExistException { dbServices.createDb(db, region, keyspace, ifNotExist); - if (wait) { + if (!async) { switch (dbServices.waitForDbStatus(db, DatabaseStatusType.ACTIVE, timeout)) { case NOT_FOUND -> throw new DatabaseNotFoundException(db); case UNAVAILABLE -> throw new InvalidDatabaseStateException(db, DatabaseStatusType.ACTIVE, DatabaseStatusType.PENDING); diff --git a/src/main/java/com/dtsx/astra/cli/db/DbCreateDotEnvCmd.java b/src/main/java/com/dtsx/astra/cli/db/DbCreateDotEnvCmd.java index 3bf6ec1..166bb3a 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbCreateDotEnvCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/DbCreateDotEnvCmd.java @@ -37,11 +37,11 @@ public class DbCreateDotEnvCmd extends AbstractDatabaseCmd { /** - * Cloud provider region to provision + * Specified a region explicitly */ @Option(name = { "-r", "--region" }, title = "DB_REGION", arity = 1, - description = "Cloud provider region to provision") - protected String region = DatabaseService.DEFAULT_REGION; + description = "Cloud provider region") + protected String region; /** * Default keyspace created with the Db diff --git a/src/main/java/com/dtsx/astra/cli/db/DbDeleteCmd.java b/src/main/java/com/dtsx/astra/cli/db/DbDeleteCmd.java index 65326c3..e78547e 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbDeleteCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/DbDeleteCmd.java @@ -22,7 +22,7 @@ import com.dtsx.astra.cli.core.out.AstraCliConsole; import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; -import com.dtsx.astra.sdk.databases.domain.DatabaseStatusType; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; @@ -39,7 +39,7 @@ public class DbDeleteCmd extends AbstractDatabaseCmd { */ @Option(name = { "--wait" }, description = "Will wait until the database become ACTIVE") - protected boolean wait = false; + protected boolean wait = true; /** * Provide a limit to the wait period in seconds, default is 180s. @@ -48,10 +48,16 @@ public class DbDeleteCmd extends AbstractDatabaseCmd { description = "Provide a limit to the wait period in seconds, default is 300s.") protected int timeout = 300; + /** + * Will not wait for the database become available. + */ + @Option(name = { "--async" }, description = "Will not wait for the resource to become available") + protected boolean async = false; + /** {@inheritDoc} */ public void execute() { dbServices.deleteDb(db); - if (wait) { + if (!async) { if (dbServices.retryUntilDbDeleted(db, timeout) >= timeout) { throw new InvalidDatabaseStateException(db, DatabaseStatusType.TERMINATED, DatabaseStatusType.TERMINATING); diff --git a/src/main/java/com/dtsx/astra/cli/db/DbDownloadScbCmd.java b/src/main/java/com/dtsx/astra/cli/db/DbDownloadScbCmd.java index 9f7212f..fd3d7aa 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbDownloadScbCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/DbDownloadScbCmd.java @@ -20,9 +20,6 @@ * #L% */ -import com.dtsx.astra.cli.core.exception.InvalidArgumentException; -import com.dtsx.astra.cli.db.exception.DatabaseNameNotUniqueException; -import com.dtsx.astra.cli.db.exception.DatabaseNotFoundException; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; @@ -33,12 +30,11 @@ */ @Command(name = "download-scb", description = "Delete an existing database") public class DbDownloadScbCmd extends AbstractDatabaseCmd { - + /** - * Cloud provider region to provision + * Specified a region explicitly */ - @Option(name = { "-r", "--region" }, - title = "REGION", + @Option(name = { "-r", "--region" }, title = "DB_REGION", arity = 1, description = "Cloud provider region") protected String region; @@ -49,10 +45,8 @@ public class DbDownloadScbCmd extends AbstractDatabaseCmd { protected String destination; /** {@inheritDoc} */ - public void execute() - throws DatabaseNameNotUniqueException, DatabaseNotFoundException, InvalidArgumentException { - DatabaseDao.getInstance() - .downloadCloudSecureBundle(db, region, destination); + public void execute() { + DaoDatabase.getInstance().downloadCloudSecureBundle(db, region, destination); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/DbListCmd.java b/src/main/java/com/dtsx/astra/cli/db/DbListCmd.java index ddf10af..107b7f7 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbListCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/DbListCmd.java @@ -33,7 +33,7 @@ public class DbListCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - DatabaseService.getInstance().listDb(); + ServiceDatabase.getInstance().listDb(); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/DbResumeCmd.java b/src/main/java/com/dtsx/astra/cli/db/DbResumeCmd.java index 8439ac9..34a4bcc 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbResumeCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/DbResumeCmd.java @@ -24,7 +24,7 @@ import com.dtsx.astra.cli.db.exception.DatabaseNameNotUniqueException; import com.dtsx.astra.cli.db.exception.DatabaseNotFoundException; import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; -import com.dtsx.astra.sdk.databases.domain.DatabaseStatusType; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; @@ -41,7 +41,7 @@ public class DbResumeCmd extends AbstractDatabaseCmd { */ @Option(name = { "--wait" }, description = "Will wait until the database become ACTIVE") - protected boolean wait = false; + protected boolean wait = true; /** * Provide a limit to the wait period in seconds, default is 180s. @@ -49,13 +49,19 @@ public class DbResumeCmd extends AbstractDatabaseCmd { @Option(name = { "--timeout" }, description = "Provide a limit to the wait period in seconds, default is 180s.") protected int timeout = 180; + + /** + * Will not wait for the database become available. + */ + @Option(name = { "--async" }, description = "Will not wait for the resource to become available") + protected boolean async = false; /** {@inheritDoc} */ public void execute() throws DatabaseNameNotUniqueException, DatabaseNotFoundException, InvalidDatabaseStateException { dbServices.resumeDb(db); - if (wait) { + if (!async) { switch (dbServices.waitForDbStatus(db, DatabaseStatusType.ACTIVE, timeout)) { case NOT_FOUND -> throw new DatabaseNotFoundException(db); case UNAVAILABLE -> throw new InvalidDatabaseStateException(db, DatabaseStatusType.ACTIVE, DatabaseStatusType.HIBERNATED); diff --git a/src/main/java/com/dtsx/astra/cli/db/DatabaseService.java b/src/main/java/com/dtsx/astra/cli/db/ServiceDatabase.java similarity index 86% rename from src/main/java/com/dtsx/astra/cli/db/DatabaseService.java rename to src/main/java/com/dtsx/astra/cli/db/ServiceDatabase.java index f046f46..eecc121 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DatabaseService.java +++ b/src/main/java/com/dtsx/astra/cli/db/ServiceDatabase.java @@ -31,11 +31,13 @@ import com.dtsx.astra.cli.db.exception.DatabaseNotFoundException; import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; import com.dtsx.astra.cli.db.exception.KeyspaceAlreadyExistException; +import com.dtsx.astra.cli.db.keyspace.ServiceKeyspace; import com.dtsx.astra.cli.utils.AstraCliUtils; import com.dtsx.astra.cli.utils.EnvFile; -import com.dtsx.astra.sdk.databases.DatabaseClient; -import com.dtsx.astra.sdk.databases.domain.*; -import com.dtsx.astra.sdk.organizations.domain.Organization; +import com.dtsx.astra.sdk.db.DatabaseClient; +import com.dtsx.astra.sdk.db.domain.*; +import com.dtsx.astra.sdk.org.OrganizationsClient; +import com.dtsx.astra.sdk.org.domain.Organization; import com.dtsx.astra.sdk.utils.ApiLocator; import org.apache.commons.lang3.StringUtils; @@ -56,16 +58,13 @@ * * @author Cedrick LUNVEN (@clunven) */ -public class DatabaseService { +public class ServiceDatabase { /** Default region. **/ public static final String DEFAULT_REGION = "us-east-1"; /** Default tier. **/ public static final String DEFAULT_TIER = "serverless"; - - /** Allow Snake case. */ - public static final String KEYSPACE_NAME_PATTERN = "^[_a-z0-9]+$"; /** Default timeout for operations. */ public static final int DEFAULT_TIMEOUT_SECONDS = 300; @@ -88,13 +87,11 @@ public class DatabaseService { static final String COLUMN_KEYSPACES = "Keyspaces"; /** working object. */ static final String DB = "Database"; - /** working object. */ - static final String KS = "Keyspace "; /** * Access to databases object. */ - DatabaseDao dbDao; + DaoDatabase dbDao; /** * JDK 11 HttpClient @@ -104,17 +101,17 @@ public class DatabaseService { /** * Singleton Pattern */ - private static DatabaseService instance; - + private static ServiceDatabase instance; + /** * Singleton Pattern. * * @return * instance of the service. */ - public static synchronized DatabaseService getInstance() { + public static synchronized ServiceDatabase getInstance() { if (null == instance) { - instance = new DatabaseService(); + instance = new ServiceDatabase(); } return instance; } @@ -122,13 +119,23 @@ public static synchronized DatabaseService getInstance() { /** * Default Constructor. */ - private DatabaseService() { - this.dbDao = DatabaseDao.getInstance(); + private ServiceDatabase() { + this.dbDao = DaoDatabase.getInstance(); client = HttpClient.newBuilder() .version(Version.HTTP_2) .connectTimeout(Duration.ofSeconds(20)) .build(); } + + /** + * Access Api devops from context. + * + * @return + * api devops + */ + private OrganizationsClient apiDevopsOrg() { + return CliContext.getInstance().getApiDevopsOrganizations(); + } /** * Wait for a DB status. @@ -215,7 +222,7 @@ public ExitCode evalReturnCode(Database db, DatabaseStatusType status, int retri */ public int retryUntilTimeoutOrSuccess(Database db, DatabaseStatusType status, int timeout) { int retries = 0; - while (retries++ < timeout && !db.getStatus().equals(status)) { + while (((timeout == 0) || (retries++ < timeout)) && !db.getStatus().equals(status)) { try { Thread.sleep(1000); db = dbDao.getDatabase(db.getInfo().getName()); @@ -294,7 +301,7 @@ public void createDb(String databaseName, String databaseRegion, String keyspace .replace(" ", "_") .replace("-", "_"); } - if (!keyspace.matches(KEYSPACE_NAME_PATTERN)) { + if (!keyspace.matches(ServiceKeyspace.KEYSPACE_NAME_PATTERN)) { throw new InvalidArgumentException("Keyspace should contain alphanumerics[a-z0-9_]"); } if (!regionMap.containsKey(databaseRegion)) { @@ -338,7 +345,7 @@ public void createDb(String databaseName, String databaseRegion, String keyspace waitForDbStatus(databaseName, DatabaseStatusType.ACTIVE, DEFAULT_TIMEOUT_SECONDS); dbStatus = dbDao.getDatabase(databaseName).getStatus(); } - case PENDING, RESUMING -> { + case PENDING, RESUMING, INITIALIZING, MAINTENANCE -> { waitForDbStatus(databaseName, DatabaseStatusType.ACTIVE, DEFAULT_TIMEOUT_SECONDS); dbStatus = dbDao.getDatabase(databaseName).getStatus(); } @@ -347,7 +354,7 @@ public void createDb(String databaseName, String databaseRegion, String keyspace // Create keyspace on existing DB when needed if (DatabaseStatusType.ACTIVE.equals(dbStatus)) { - createKeyspace(databaseName, keyspace, true); + ServiceKeyspace.getInstance().createKeyspace(databaseName, keyspace, true); } else { throw new InvalidDatabaseStateException(databaseName, DatabaseStatusType.ACTIVE, dbStatus); } @@ -377,32 +384,7 @@ public void listDb() { AstraCliConsole.printShellTable(sht); } - /** - * List keyspaces of a database. - * - * @param databaseName - * database name - * @throws DatabaseNameNotUniqueException - * multiple databases with the name. - * @throws DatabaseNotFoundException - * database name has not been found. - */ - public void listKeyspaces(String databaseName) - throws DatabaseNameNotUniqueException, DatabaseNotFoundException { - Database db = dbDao.getDatabase(databaseName); - ShellTable sht = new ShellTable(); - sht.addColumn(COLUMN_NAME, 20); - db.getInfo().getKeyspaces().forEach(ks -> { - Map rf = new HashMap<>(); - if (db.getInfo().getKeyspace().equals(ks)) { - rf.put(COLUMN_NAME, ks + " (default)"); - } else { - rf.put(COLUMN_NAME, ks); - } - sht.getCellValues().add(rf); - }); - AstraCliConsole.printShellTable(sht); - } + /** * Delete a database if exist. @@ -558,48 +540,39 @@ public void showDb(String databaseName, DbGetCmd.DbGetKeys key) } } - + /** - * Create a keyspace if not exist. - * - * @param ifNotExist - * flag to disable error if already exists - * @param databaseName - * db name - * @param keyspaceName - * ks name - * @throws DatabaseNameNotUniqueException - * error if db name is not unique - * @throws DatabaseNotFoundException - * error is db is not found - * @throws InvalidArgumentException - * invalid parameter - * @throws KeyspaceAlreadyExistException - * keyspace exist and --if-not-exist option not provided + * Retrieve region name. + * + * @param region + * forced region name + * @return + * region name */ - public void createKeyspace(String databaseName, String keyspaceName, boolean ifNotExist) - throws DatabaseNameNotUniqueException, DatabaseNotFoundException, - InvalidArgumentException, KeyspaceAlreadyExistException { - - // Validate keyspace names - if (!keyspaceName.matches(KEYSPACE_NAME_PATTERN)) - throw new InvalidArgumentException("The keyspace name is not valid, please use snake_case: [a-z0-9_]"); - - if (dbDao.getDatabase(databaseName).getInfo().getKeyspaces().contains(keyspaceName)) { - if (ifNotExist) { - LoggerShell.info("%s '%s' already exists. Connecting to keyspace.".formatted(KS, keyspaceName)); - } else { - throw new KeyspaceAlreadyExistException(keyspaceName, databaseName); - } - } else { - try { - dbDao.getRequiredDatabaseClient(databaseName).createKeyspace(keyspaceName); - LoggerShell.info("%s '%s' is creating.".formatted(KS, keyspaceName)); - } catch(Exception e) { - throw new InvalidDatabaseStateException(databaseName, DatabaseStatusType.ACTIVE, - dbDao.getDatabase(databaseName).getStatus()); - } + private String retrieveDatabaseRegion(Database db, String region) { + + if (region == null) + region = db.getInfo().getRegion(); + + // Region is valid + Set availableRegions = apiDevopsOrg() + .regionsServerless() + .map(DatabaseRegionServerless::getName) + .collect(Collectors.toSet()); + if (!availableRegions.contains(region)) { + throw new InvalidArgumentException("Provided region is invalid pick one of " + availableRegions); + } + + // Db is actually present in that region + Map datacenters = db + .getInfo().getDatacenters() + .stream().collect(Collectors.toMap(Datacenter::getRegion, Function.identity())); + if (!datacenters.containsKey(region)) { + throw new InvalidArgumentException("Region %s is not part of existing regions %s, use flag -r to specify region name" + .formatted(region, datacenters.keySet().toString())); } + + return region; } /** @@ -632,31 +605,12 @@ public void generateDotEnvFile(String dbName, String ks, String region, String d // Database Database db = dbDao.getDatabase(dbName); + region = retrieveDatabaseRegion(db, region); Map datacenters = db .getInfo().getDatacenters() .stream().collect(Collectors.toMap(Datacenter::getRegion, Function.identity())); envFile.getKeys().put(EnvFile.EnvKey.ASTRA_DB_ID, db.getId()); envFile.getKeys().put(EnvFile.EnvKey.ASTRA_DB_REGION, db.getInfo().getRegion()); - - // Parameter Validations - Set availableRegions = CliContext.getInstance() - .getApiDevopsOrganizations() - .regionsServerless() - .map(DatabaseRegionServerless::getName) - .collect(Collectors.toSet()); - - if (region == null) - region = db.getInfo().getRegion(); - if (datacenters.size() == 1) - region = datacenters.keySet().iterator().next(); - - if (!datacenters.containsKey(region)) { - throw new InvalidArgumentException("Region %s is not part of existing regions %s, use flag -r to specify region name" - .formatted(region, datacenters.keySet().toString())); - } - if (!availableRegions.contains(region)) { - throw new InvalidArgumentException("Provided region is invalid pick one of " + availableRegions); - } envFile.getKeys().put(EnvFile.EnvKey.ASTRA_DB_SECURE_BUNDLE_URL, datacenters.get(region).getSecureBundleUrl()); Set dbRegions = db.getInfo().getDatacenters() @@ -692,5 +646,36 @@ public void generateDotEnvFile(String dbName, String ks, String region, String d envFile.save(); } + /** + * Build Swagger Url based on db and region. + * + * @param dbName + * database name + * @param region + * database region + * @return + * swagger url + */ + public String swaggerUrl(String dbName, String region) { + Database db = dbDao.getDatabase(dbName); + return ApiLocator.getApiRestEndpoint(db.getId(), retrieveDatabaseRegion(db, region)) + "/swagger-ui/"; + } + + /** + * Build Playground Url based on db and region. + * + * @param dbName + * database name + * @param region + * database region + * @return + * swagger url + */ + public String graphQLPlayground(String dbName, String region) { + Database db = dbDao.getDatabase(dbName); + return ApiLocator.getApiGraphQLEndPoint(db.getId(), retrieveDatabaseRegion(db, region)) + "/playground"; + } + + } diff --git a/src/main/java/com/dtsx/astra/cli/db/cqlsh/DbCqlShellCmd.java b/src/main/java/com/dtsx/astra/cli/db/cqlsh/DbCqlShellCmd.java index df36bf7..01980e6 100644 --- a/src/main/java/com/dtsx/astra/cli/db/cqlsh/DbCqlShellCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/cqlsh/DbCqlShellCmd.java @@ -76,7 +76,7 @@ public void execute() CqlShellOption options = new CqlShellOption( cqlShOptionVersion, cqlShOptionDebug, cqlshOptionEncoding, cqlshOptionExecute,cqlshOptionFile,cqlshOptionKeyspace); - CqlShellService.getInstance().run(options, db); + ServiceCqlShell.getInstance().run(options, db); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/cqlsh/CqlShellService.java b/src/main/java/com/dtsx/astra/cli/db/cqlsh/ServiceCqlShell.java similarity index 95% rename from src/main/java/com/dtsx/astra/cli/db/cqlsh/CqlShellService.java rename to src/main/java/com/dtsx/astra/cli/db/cqlsh/ServiceCqlShell.java index 7b3de4e..cf89ac4 100644 --- a/src/main/java/com/dtsx/astra/cli/db/cqlsh/CqlShellService.java +++ b/src/main/java/com/dtsx/astra/cli/db/cqlsh/ServiceCqlShell.java @@ -24,10 +24,10 @@ import com.dtsx.astra.cli.core.exception.CannotStartProcessException; import com.dtsx.astra.cli.core.exception.FileSystemException; import com.dtsx.astra.cli.core.out.LoggerShell; -import com.dtsx.astra.cli.db.DatabaseDao; +import com.dtsx.astra.cli.db.DaoDatabase; import com.dtsx.astra.cli.utils.AstraCliUtils; import com.dtsx.astra.cli.utils.FileUtils; -import com.dtsx.astra.sdk.databases.domain.Database; +import com.dtsx.astra.sdk.db.domain.Database; import java.io.*; import java.nio.file.Files; @@ -40,7 +40,7 @@ * * @author Cedrick LUNVEN (@clunven) */ -public class CqlShellService { +public class ServiceCqlShell { /** Patch for cqlShell. */ private static final String VERSION_TO_REPLACE = "|| [ \"$version\" = \"2.7\" ]"; @@ -52,7 +52,7 @@ public class CqlShellService { CqlShellConfig settings; /** Access to Database client */ - DatabaseDao dbDao; + DaoDatabase dbDao; /** Local installation folder for CqlSh. */ File cqlshLocalFolder; @@ -61,7 +61,7 @@ public class CqlShellService { String cqlshExecutable; /** Singleton Pattern. */ - private static CqlShellService instance; + private static ServiceCqlShell instance; /** * Singleton Pattern. @@ -69,9 +69,9 @@ public class CqlShellService { * @return * instance of the service. */ - public static synchronized CqlShellService getInstance() { + public static synchronized ServiceCqlShell getInstance() { if (null == instance) { - instance = new CqlShellService(); + instance = new ServiceCqlShell(); } return instance; } @@ -79,8 +79,8 @@ public static synchronized CqlShellService getInstance() { /** * Default constructor */ - private CqlShellService() { - this.dbDao = DatabaseDao.getInstance(); + private ServiceCqlShell() { + this.dbDao = DaoDatabase.getInstance(); settings = new CqlShellConfig( AstraCliUtils.readProperty("cqlsh.url"), diff --git a/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbCountCmd.java b/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbCountCmd.java index d3d2652..41d9d26 100644 --- a/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbCountCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbCountCmd.java @@ -33,7 +33,7 @@ public class DbCountCmd extends AbstractDsbulkDataCmd { /** {@inheritDoc} */ @Override public void execute() { - DsBulkService.getInstance().count(this); + ServiceDsBulk.getInstance().count(this); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbLoadCmd.java b/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbLoadCmd.java index 5c822dc..582cc4e 100644 --- a/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbLoadCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbLoadCmd.java @@ -43,7 +43,7 @@ public class DbLoadCmd extends AbstractDsbulkDataCmd { /** {@inheritDoc} */ @Override public void execute() { - DsBulkService.getInstance().load(this); + ServiceDsBulk.getInstance().load(this); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbUnLoadCmd.java b/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbUnLoadCmd.java index e3cafc4..1049c5d 100644 --- a/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbUnLoadCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/dsbulk/DbUnLoadCmd.java @@ -34,7 +34,7 @@ public class DbUnLoadCmd extends AbstractDsbulkDataCmd { /** {@inheritDoc} */ @Override public void execute() { - DsBulkService.getInstance().unload(this); + ServiceDsBulk.getInstance().unload(this); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/dsbulk/DsBulkService.java b/src/main/java/com/dtsx/astra/cli/db/dsbulk/ServiceDsBulk.java similarity index 96% rename from src/main/java/com/dtsx/astra/cli/db/dsbulk/DsBulkService.java rename to src/main/java/com/dtsx/astra/cli/db/dsbulk/ServiceDsBulk.java index 236e4e9..f5d8fe1 100644 --- a/src/main/java/com/dtsx/astra/cli/db/dsbulk/DsBulkService.java +++ b/src/main/java/com/dtsx/astra/cli/db/dsbulk/ServiceDsBulk.java @@ -24,10 +24,10 @@ import com.dtsx.astra.cli.core.exception.CannotStartProcessException; import com.dtsx.astra.cli.core.exception.FileSystemException; import com.dtsx.astra.cli.core.out.LoggerShell; -import com.dtsx.astra.cli.db.DatabaseDao; +import com.dtsx.astra.cli.db.DaoDatabase; import com.dtsx.astra.cli.utils.AstraCliUtils; import com.dtsx.astra.cli.utils.FileUtils; -import com.dtsx.astra.sdk.databases.domain.Database; +import com.dtsx.astra.sdk.db.domain.Database; import java.io.File; import java.io.IOException; @@ -41,7 +41,7 @@ * * @author Cedrick LUNVEN (@clunven) */ -public class DsBulkService { +public class ServiceDsBulk { /** prefix in definition. */ static final String DSBULK_PREFIX = "dsbulk-"; @@ -89,12 +89,12 @@ public String getOp() { String dsbulkExecutable; /** Access to databases object. */ - DatabaseDao dbDao; + DaoDatabase dbDao; /** * Singleton Pattern */ - private static DsBulkService instance; + private static ServiceDsBulk instance; /** * Singleton Pattern. @@ -102,9 +102,9 @@ public String getOp() { * @return * instance of the service. */ - public static synchronized DsBulkService getInstance() { + public static synchronized ServiceDsBulk getInstance() { if (null == instance) { - instance = new DsBulkService(); + instance = new ServiceDsBulk(); } return instance; } @@ -112,12 +112,12 @@ public static synchronized DsBulkService getInstance() { /** * Initialization. */ - private DsBulkService() { + private ServiceDsBulk() { config = new DsBulkConfig( AstraCliUtils.readProperty("dsbulk.url"), AstraCliUtils.readProperty("dsbulk.version")); - this.dbDao = DatabaseDao.getInstance(); + this.dbDao = DaoDatabase.getInstance(); this.dsbulkLocalFolder = new File(AstraCliUtils.ASTRA_HOME + File.separator diff --git a/src/main/java/com/dtsx/astra/cli/db/exception/InvalidDatabaseStateException.java b/src/main/java/com/dtsx/astra/cli/db/exception/InvalidDatabaseStateException.java index d873bc6..3a3a58c 100644 --- a/src/main/java/com/dtsx/astra/cli/db/exception/InvalidDatabaseStateException.java +++ b/src/main/java/com/dtsx/astra/cli/db/exception/InvalidDatabaseStateException.java @@ -20,7 +20,7 @@ * #L% */ -import com.dtsx.astra.sdk.databases.domain.DatabaseStatusType; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; import java.io.Serial; diff --git a/src/main/java/com/dtsx/astra/cli/db/exception/KeyspaceAlreadyExistException.java b/src/main/java/com/dtsx/astra/cli/db/exception/KeyspaceAlreadyExistException.java index 2df7067..98cb140 100644 --- a/src/main/java/com/dtsx/astra/cli/db/exception/KeyspaceAlreadyExistException.java +++ b/src/main/java/com/dtsx/astra/cli/db/exception/KeyspaceAlreadyExistException.java @@ -23,7 +23,7 @@ import java.io.Serial; /** - * Database not found + * Keyspace already exists * * @author Cedrick LUNVEN (@clunven) */ diff --git a/src/main/java/com/dtsx/astra/cli/db/exception/RegionAlreadyExistException.java b/src/main/java/com/dtsx/astra/cli/db/exception/RegionAlreadyExistException.java new file mode 100644 index 0000000..a438019 --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/db/exception/RegionAlreadyExistException.java @@ -0,0 +1,50 @@ +package com.dtsx.astra.cli.db.exception; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.Serial; + +/** + * Regions already exists + * + * @author Cedrick LUNVEN (@clunven) + */ +public class RegionAlreadyExistException extends RuntimeException { + + /** Serial Number. */ + @Serial + private static final long serialVersionUID = 968018206118357644L; + + /** + * Constructor with region name + * + * @param regionName + * region name + * @param dbname + * database name + */ + public RegionAlreadyExistException(String regionName, String dbname) { + super(("Region '%s' already exists for database %s. " + + "Cannot create another region with same name. " + + "Use flag --if-not-exist to connect to the existing region.").formatted(regionName, dbname)); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/db/keyspace/DbCreateKeyspaceCmd.java b/src/main/java/com/dtsx/astra/cli/db/keyspace/DbCreateKeyspaceCmd.java index 9a97b8e..ac2666c 100644 --- a/src/main/java/com/dtsx/astra/cli/db/keyspace/DbCreateKeyspaceCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/keyspace/DbCreateKeyspaceCmd.java @@ -22,10 +22,10 @@ import com.dtsx.astra.cli.core.out.LoggerShell; import com.dtsx.astra.cli.db.AbstractDatabaseCmd; -import com.dtsx.astra.cli.db.DatabaseService; +import com.dtsx.astra.cli.db.ServiceDatabase; import com.dtsx.astra.cli.db.exception.DatabaseNotFoundException; import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; -import com.dtsx.astra.sdk.databases.domain.DatabaseStatusType; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; import com.github.rvesse.airline.annotations.restrictions.Required; @@ -56,19 +56,26 @@ public class DbCreateKeyspaceCmd extends AbstractDatabaseCmd { */ @Option(name = { "--wait" }, description = "Will wait until the database become ACTIVE") - protected boolean wait = false; + protected boolean wait = true; + + /** + * Will wait until the database become ACTIVE. + */ + @Option(name = { "--async" }, + description = "Will wait until the database become ACTIVE") + protected boolean async = false; /** * Provide a limit to the wait period in seconds, default is 180s. */ @Option(name = { "--timeout" }, description = "Provide a limit to the wait period in seconds, default is 300s.") - protected int timeout = DatabaseService.DEFAULT_TIMEOUT_SECONDS; + protected int timeout = ServiceDatabase.DEFAULT_TIMEOUT_SECONDS; /** {@inheritDoc} */ public void execute() { - dbServices.createKeyspace(db, keyspace, ifNotExist); - if (wait) { + ServiceKeyspace.getInstance().createKeyspace(db, keyspace, ifNotExist); + if (!async) { switch (dbServices.waitForDbStatus(db, DatabaseStatusType.ACTIVE, timeout)) { case NOT_FOUND -> throw new DatabaseNotFoundException(db); case UNAVAILABLE -> throw new InvalidDatabaseStateException(db, DatabaseStatusType.ACTIVE, DatabaseStatusType.MAINTENANCE); diff --git a/src/main/java/com/dtsx/astra/cli/db/keyspace/DbListKeyspacesCmd.java b/src/main/java/com/dtsx/astra/cli/db/keyspace/DbListKeyspacesCmd.java index f1d4963..1bbec47 100644 --- a/src/main/java/com/dtsx/astra/cli/db/keyspace/DbListKeyspacesCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/keyspace/DbListKeyspacesCmd.java @@ -33,7 +33,7 @@ public class DbListKeyspacesCmd extends AbstractDatabaseCmd { /** {@inheritDoc} */ public void execute() { - dbServices.listKeyspaces(db); + ServiceKeyspace.getInstance().listKeyspaces(db); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/keyspace/ServiceKeyspace.java b/src/main/java/com/dtsx/astra/cli/db/keyspace/ServiceKeyspace.java new file mode 100644 index 0000000..ebeb2ea --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/db/keyspace/ServiceKeyspace.java @@ -0,0 +1,148 @@ +package com.dtsx.astra.cli.db.keyspace; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.exception.InvalidArgumentException; +import com.dtsx.astra.cli.core.out.AstraCliConsole; +import com.dtsx.astra.cli.core.out.LoggerShell; +import com.dtsx.astra.cli.core.out.ShellTable; +import com.dtsx.astra.cli.db.DaoDatabase; +import com.dtsx.astra.cli.db.exception.DatabaseNameNotUniqueException; +import com.dtsx.astra.cli.db.exception.DatabaseNotFoundException; +import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; +import com.dtsx.astra.cli.db.exception.KeyspaceAlreadyExistException; +import com.dtsx.astra.sdk.db.domain.Database; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; + +import java.util.HashMap; +import java.util.Map; + +/** + * Group services related to keyspaces. + */ +public class ServiceKeyspace { + + /** column names. */ + static final String COLUMN_NAME = "Name"; + + /** working object. */ + static final String KS = "Keyspace "; + + /** Allow Snake case. */ + public static final String KEYSPACE_NAME_PATTERN = "^[_a-z0-9]+$"; + + /** + * Singleton Pattern + */ + private static ServiceKeyspace instance; + + /** + * Access to databases object. + */ + private final DaoDatabase dbDao; + + /** + * Singleton Pattern. + * + * @return + * instance of the service. + */ + public static synchronized ServiceKeyspace getInstance() { + if (null == instance) { + instance = new ServiceKeyspace(); + } + return instance; + } + + /** + * Default Constructor. + */ + private ServiceKeyspace() { + this.dbDao = DaoDatabase.getInstance(); + } + + /** + * List keyspaces of a database. + * + * @param databaseName + * database name + */ + public void listKeyspaces(String databaseName) { + Database db = dbDao.getDatabase(databaseName); + ShellTable sht = new ShellTable(); + sht.addColumn(COLUMN_NAME, 20); + db.getInfo().getKeyspaces().forEach(ks -> { + Map rf = new HashMap<>(); + if (db.getInfo().getKeyspace().equals(ks)) { + rf.put(COLUMN_NAME, ks + " (default)"); + } else { + rf.put(COLUMN_NAME, ks); + } + sht.getCellValues().add(rf); + }); + AstraCliConsole.printShellTable(sht); + } + + /** + * Create a keyspace if not exist. + * + * @param ifNotExist + * flag to disable error if already exists + * @param databaseName + * db name + * @param keyspaceName + * ks name + * @throws DatabaseNameNotUniqueException + * error if db name is not unique + * @throws DatabaseNotFoundException + * error is db is not found + * @throws InvalidArgumentException + * invalid parameter + * @throws KeyspaceAlreadyExistException + * keyspace exist and --if-not-exist option not provided + */ + public void createKeyspace(String databaseName, String keyspaceName, boolean ifNotExist) + throws DatabaseNameNotUniqueException, DatabaseNotFoundException, + InvalidArgumentException, KeyspaceAlreadyExistException { + + // Validate keyspace names + if (!keyspaceName.matches(KEYSPACE_NAME_PATTERN)) + throw new InvalidArgumentException("The keyspace name is not valid, please use snake_case: [a-z0-9_]"); + + if (dbDao.getDatabase(databaseName).getInfo().getKeyspaces().contains(keyspaceName)) { + if (ifNotExist) { + LoggerShell.info("%s '%s' already exists. Connecting to keyspace.".formatted(KS, keyspaceName)); + } else { + throw new KeyspaceAlreadyExistException(keyspaceName, databaseName); + } + } else { + try { + dbDao.getRequiredDatabaseClient(databaseName).createKeyspace(keyspaceName); + LoggerShell.info("%s '%s' is creating.".formatted(KS, keyspaceName)); + } catch(Exception e) { + throw new InvalidDatabaseStateException(databaseName, DatabaseStatusType.ACTIVE, + dbDao.getDatabase(databaseName).getStatus()); + } + } + } + + +} diff --git a/src/main/java/com/dtsx/astra/cli/db/region/DbCreateRegionCmd.java b/src/main/java/com/dtsx/astra/cli/db/region/DbCreateRegionCmd.java new file mode 100644 index 0000000..510a4df --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/db/region/DbCreateRegionCmd.java @@ -0,0 +1,99 @@ +package com.dtsx.astra.cli.db.region; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.out.LoggerShell; +import com.dtsx.astra.cli.db.AbstractDatabaseCmd; +import com.dtsx.astra.cli.db.ServiceDatabase; +import com.dtsx.astra.cli.db.exception.DatabaseNotFoundException; +import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; +import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.Option; +import com.github.rvesse.airline.annotations.restrictions.Required; + +/** + * Expand database to a new region. + * + * @author Cedrick LUNVEN (@clunven) + */ +@Command(name = "create-region", description = "Expand database to a new region") +public class DbCreateRegionCmd extends AbstractDatabaseCmd { + + /** Provide a keyspace Name. */ + @Required + @Option(name = {"-r", "--region" }, + title = "REGION", + arity = 1, + description = "Name of the region to create") + public String region; + + @Option(name = {"-c", "--cloud" }, + title = "CLOUD", + arity = 1, + description = "Name of the cloud provider") + public String cloudProvider; + + @Option(name = {"-t", "--tier" }, + title = "CLOUD", + arity = 1, + description = "Name of the tiers") + public String tier = "serverless"; + + /** Option. */ + @Option(name = { "--if-not-exist" }, + description = "will create a new DB only if none with same name") + protected boolean ifNotExist = false; + + /** + * Will wait until the database become ACTIVE. + */ + @Option(name = { "--wait" }, + description = "Will wait until the database become ACTIVE") + protected boolean wait = true; + + /** + * Will wait until the database become ACTIVE. + */ + @Option(name = { "--async" }, + description = "Will wait until the database become ACTIVE") + protected boolean async = false; + + /** + * Provide a limit to the wait period in seconds, default is 180s. + */ + @Option(name = { "--timeout" }, + description = "Max wait time in seconds, default+1800, 0 = no timeout.") + protected int timeout = 1800; + + /** {@inheritDoc} */ + public void execute() { + ServiceRegion.getInstance().addRegion(db, region, cloudProvider, tier, ifNotExist); + if (!async) { + switch (dbServices.waitForDbStatus(db, DatabaseStatusType.ACTIVE, timeout)) { + case NOT_FOUND -> throw new DatabaseNotFoundException(db); + case UNAVAILABLE -> throw new InvalidDatabaseStateException(db, DatabaseStatusType.ACTIVE, DatabaseStatusType.MAINTENANCE); + default -> LoggerShell.success("Database '%s' is ready.".formatted(db)); + } + } + } +} diff --git a/src/main/java/com/dtsx/astra/cli/db/region/DbDeleteRegionCmd.java b/src/main/java/com/dtsx/astra/cli/db/region/DbDeleteRegionCmd.java new file mode 100644 index 0000000..68013a6 --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/db/region/DbDeleteRegionCmd.java @@ -0,0 +1,80 @@ +package com.dtsx.astra.cli.db.region; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.out.AstraCliConsole; +import com.dtsx.astra.cli.core.out.LoggerShell; +import com.dtsx.astra.cli.db.AbstractDatabaseCmd; +import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.Option; +import com.github.rvesse.airline.annotations.restrictions.Required; + +/** + * Delete a region from a db. + * + * @author Cedrick LUNVEN (@clunven) + */ +@Command(name = "delete-region", description = "Delete a region from a database") +public class DbDeleteRegionCmd extends AbstractDatabaseCmd { + + /** Provide a keyspace Name. */ + @Required + @Option(name = {"-r", "--region" }, + title = "REGION", + arity = 1, + description = "Name of the region to create") + public String region; + + /** + * Will wait until the database become ACTIVE. + */ + @Option(name = { "--wait" }, + description = "Will wait until the database become ACTIVE") + protected boolean wait = true; + + /** + * Provide a limit to the wait period in seconds, default is 180s. + */ + @Option(name = { "--timeout" }, + description = "Max wait time in seconds, default+1800, 0 = no timeout.") + protected int timeout = 1800; + + /** + * Will wait until the database become ACTIVE. + */ + @Option(name = { "--async" }, + description = "Will wait until the database become ACTIVE") + protected boolean async = false; + + /** {@inheritDoc} */ + public void execute() { + ServiceRegion.getInstance().deleteRegion(db, region); + if (!async) { + if (ServiceRegion.getInstance().retryUntilRegionDeleted(db, region, timeout) >= timeout) { + throw new InvalidDatabaseStateException(db, DatabaseStatusType.MAINTENANCE, DatabaseStatusType.ACTIVE); + } else { + AstraCliConsole.outputSuccess("Region %s has been deleted".formatted(region)); + } + } + } +} diff --git a/src/main/java/com/dtsx/astra/cli/db/DbListRegionsClassicCmd.java b/src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsClassicCmd.java similarity index 90% rename from src/main/java/com/dtsx/astra/cli/db/DbListRegionsClassicCmd.java rename to src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsClassicCmd.java index b221b86..03f1f01 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbListRegionsClassicCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsClassicCmd.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.db; +package com.dtsx.astra.cli.db.region; /*- * #%L @@ -21,7 +21,7 @@ */ import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.dtsx.astra.cli.org.OrganizationService; +import com.dtsx.astra.cli.org.ServiceOrganization; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; @@ -49,7 +49,7 @@ public class DbListRegionsClassicCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OrganizationService.getInstance().listRegionsDbClassic(cloud, filter); + ServiceOrganization.getInstance().listRegionsDbClassic(cloud, filter); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsCmd.java b/src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsCmd.java new file mode 100644 index 0000000..2d9e041 --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsCmd.java @@ -0,0 +1,39 @@ +package com.dtsx.astra.cli.db.region; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.out.LoggerShell; +import com.dtsx.astra.cli.db.AbstractDatabaseCmd; +import com.github.rvesse.airline.annotations.Command; + +/** + * List regions for a DB. + * + * @author Cedrick LUNVEN (@clunven) + */ +@Command(name = "list-regions", description = "List regions for a database") +public class DbListRegionsCmd extends AbstractDatabaseCmd { + + /** {@inheritDoc} */ + public void execute() { + ServiceRegion.getInstance().listRegions(db); + } +} diff --git a/src/main/java/com/dtsx/astra/cli/db/DbListRegionsServerlessCmd.java b/src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsServerlessCmd.java similarity index 90% rename from src/main/java/com/dtsx/astra/cli/db/DbListRegionsServerlessCmd.java rename to src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsServerlessCmd.java index f8cee54..468cf6d 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbListRegionsServerlessCmd.java +++ b/src/main/java/com/dtsx/astra/cli/db/region/DbListRegionsServerlessCmd.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.db; +package com.dtsx.astra.cli.db.region; /*- * #%L @@ -21,7 +21,7 @@ */ import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.dtsx.astra.cli.org.OrganizationService; +import com.dtsx.astra.cli.org.ServiceOrganization; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; @@ -49,7 +49,7 @@ public class DbListRegionsServerlessCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OrganizationService.getInstance().listRegionsDbServerless(cloud, filter); + ServiceOrganization.getInstance().listRegionsDbServerless(cloud, filter); } } diff --git a/src/main/java/com/dtsx/astra/cli/db/region/ServiceRegion.java b/src/main/java/com/dtsx/astra/cli/db/region/ServiceRegion.java new file mode 100644 index 0000000..0f7c21c --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/db/region/ServiceRegion.java @@ -0,0 +1,212 @@ +package com.dtsx.astra.cli.db.region; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.CliContext; +import com.dtsx.astra.cli.core.out.AstraCliConsole; +import com.dtsx.astra.cli.core.out.LoggerShell; +import com.dtsx.astra.cli.core.out.ShellTable; +import com.dtsx.astra.cli.db.DaoDatabase; +import com.dtsx.astra.cli.db.exception.InvalidDatabaseStateException; +import com.dtsx.astra.cli.db.exception.RegionAlreadyExistException; +import com.dtsx.astra.sdk.db.DatabasesClient; +import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import com.dtsx.astra.sdk.db.domain.Database; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; +import com.dtsx.astra.sdk.db.domain.Datacenter; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Operation on regions + */ +public class ServiceRegion { + + /** column names. */ + public static final String REGION = "Region"; + + /** column names. */ + public static final String COLUMN_CLOUD = "Cloud Provider"; + + /** column names. */ + public static final String COLUMN_REGION_NAME = "Region"; + + /** column names. */ + public static final String COLUMN_REGION_STATUS = "Status"; + + /** column names. */ + public static final String COLUMN_REGION_TIER = "Tier"; + + /** + * Singleton Pattern + */ + private static ServiceRegion instance; + + /** + * Access to databases object. + */ + private final DaoDatabase dbDao; + + /** + * Singleton Pattern. + * + * @return + * instance of the service. + */ + public static synchronized ServiceRegion getInstance() { + if (null == instance) { + instance = new ServiceRegion(); + } + return instance; + } + + /** + * Default Constructor. + */ + private ServiceRegion() { + this.dbDao = DaoDatabase.getInstance(); + } + + /** + * Access Api devops from context. + * + * @return + * api devops + */ + private DatabasesClient apiDevopsDb() { + return CliContext.getInstance().getApiDevopsDatabases(); + } + + /** + * List keyspaces of a database. + * + * @param databaseName + * database name + */ + public void listRegions(String databaseName) { + Database db = dbDao.getDatabase(databaseName); + ShellTable sht = new ShellTable(); + sht.addColumn(COLUMN_CLOUD, 15); + sht.addColumn(COLUMN_REGION_NAME, 20); + sht.addColumn(COLUMN_REGION_TIER, 15); + sht.addColumn(COLUMN_REGION_STATUS, 15); + db.getInfo().getDatacenters().forEach(dc -> { + Map rf = new HashMap<>(); + rf.put(COLUMN_CLOUD, dc.getCloudProvider().name().toLowerCase()); + if (db.getInfo().getRegion().equals(dc.getRegion())) { + rf.put(COLUMN_REGION_NAME, dc.getRegion() + " (default)"); + } else { + rf.put(COLUMN_REGION_NAME, dc.getRegion()); + } + rf.put(COLUMN_REGION_TIER, dc.getTier()); + rf.put(COLUMN_REGION_STATUS, dc.getStatus()); + sht.getCellValues().add(rf); + }); + AstraCliConsole.printShellTable(sht); + } + + /** + * Adding a region to a DB if not exists. + * + * @param databaseName + * database name + * @param regionName + * region name + * @param cloudProvider + * cloud provider + * @param tier + * tier + * @param ifNotExist + * only operate if the region does not exist + */ + public void addRegion(String databaseName, String regionName, String cloudProvider, String tier, boolean ifNotExist) { + Database db = dbDao.getDatabase(databaseName); + Set regionsDb = db.getInfo() + .getDatacenters().stream() + .map(Datacenter::getRegion) + .collect(Collectors.toSet()); + if (regionsDb.contains(regionName)) { + if (ifNotExist) { + LoggerShell.info("No action as %s '%s' already exists.".formatted(REGION, regionName)); + } else { + throw new RegionAlreadyExistException(regionName, databaseName); + } + } else { + try { + CloudProviderType cloud = db.getInfo().getCloudProvider(); + if (cloudProvider != null) cloud = CloudProviderType.valueOf(cloudProvider.toUpperCase()); + apiDevopsDb().database(db.getId()).addRegion(tier, cloud, regionName); + LoggerShell.info("%s '%s' is creating.".formatted(REGION, regionName)); + } catch(Exception e) { + throw new InvalidDatabaseStateException(databaseName, DatabaseStatusType.ACTIVE, + dbDao.getDatabase(databaseName).getStatus()); + } + } + } + + /** + * Loop and wait 1s in between 2 tests. + * + * @param dbName + * database name + * @param regionName + * region to be deleted + * @param timeout + * timeout is max retries + * @return + * max retried + */ + public int retryUntilRegionDeleted(String dbName, String regionName, int timeout) { + int retries = 0; + Database db = dbDao.getDatabase(dbName); + while (((retries++ < timeout) || (timeout == 0)) && + apiDevopsDb().database(db.getId()).findRegion(regionName).isPresent()) { + try { + Thread.sleep(1000); + LoggerShell.debug("Waiting for %s to be deleted ( %d / %d )".formatted(REGION, retries, timeout)); + } catch (InterruptedException e) { + LoggerShell.error("Interrupted operation: %s".formatted(e.getMessage())); + Thread.currentThread().interrupt(); + } + } + return retries; + } + + /** + * Delete a region to a DB + * + * @param databaseName + * database name + * @param regionName + * region name + */ + public void deleteRegion(String databaseName, String regionName) { + // Throw db not found exception if database does not exist + Database db = dbDao.getDatabase(databaseName); + // Throw region not found exception if region does not exist + apiDevopsDb().database(db.getId()).deleteRegion(regionName); + LoggerShell.info("%s '%s' is deleting.".formatted(REGION, regionName)); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/db/tool/DbGraphqlPlaygroundCmd.java b/src/main/java/com/dtsx/astra/cli/db/tool/DbGraphqlPlaygroundCmd.java new file mode 100644 index 0000000..ef55f02 --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/db/tool/DbGraphqlPlaygroundCmd.java @@ -0,0 +1,49 @@ +package com.dtsx.astra.cli.db.tool; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.out.AstraCliConsole; +import com.dtsx.astra.cli.core.out.LoggerShell; +import com.dtsx.astra.cli.db.AbstractDatabaseCmd; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.Option; + +/** + * Open a browser with playground. + * + * @author @clunven + */ +@Command(name = "playground", description = "Expand database to a new region") +public class DbGraphqlPlaygroundCmd extends AbstractDatabaseCmd { + + /** + * Specified a region explicitly + */ + @Option(name = { "-r", "--region" }, title = "DB_REGION", arity = 1, + description = "Cloud provider region") + protected String region; + + /** {@inheritDoc} */ + public void execute() { + AstraCliConsole.outputSuccess(dbServices.graphQLPlayground(db, region)); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/db/tool/DbSwaggerUICmd.java b/src/main/java/com/dtsx/astra/cli/db/tool/DbSwaggerUICmd.java new file mode 100644 index 0000000..baddba5 --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/db/tool/DbSwaggerUICmd.java @@ -0,0 +1,48 @@ +package com.dtsx.astra.cli.db.tool; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.out.AstraCliConsole; +import com.dtsx.astra.cli.db.AbstractDatabaseCmd; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.Option; + +/** + * Open a browser with playground. + * + * @author @clunven + */ +@Command(name = "swagger", description = "Open the swagger user interface") +public class DbSwaggerUICmd extends AbstractDatabaseCmd { + + /** + * Specified a region explicitly + */ + @Option(name = { "-r", "--region" }, title = "DB_REGION", arity = 1, + description = "Cloud provider region") + protected String region; + + /** {@inheritDoc} */ + public void execute() { + AstraCliConsole.outputSuccess(dbServices.swaggerUrl(db, region)); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/iam/OperationIam.java b/src/main/java/com/dtsx/astra/cli/iam/OperationIam.java deleted file mode 100644 index bb29f59..0000000 --- a/src/main/java/com/dtsx/astra/cli/iam/OperationIam.java +++ /dev/null @@ -1,258 +0,0 @@ -package com.dtsx.astra.cli.iam; - -/*- - * #%L - * Astra Cli - * %% - * Copyright (C) 2022 DataStax - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.dtsx.astra.cli.core.CliContext; -import com.dtsx.astra.cli.core.ExitCode; -import com.dtsx.astra.cli.core.out.AstraCliConsole; -import com.dtsx.astra.cli.core.out.JsonOutput; -import com.dtsx.astra.cli.core.out.ShellTable; -import com.dtsx.astra.cli.iam.exception.RoleNotFoundException; -import com.dtsx.astra.cli.iam.exception.UserAlreadyExistException; -import com.dtsx.astra.cli.iam.exception.UserNotFoundException; -import com.dtsx.astra.sdk.organizations.OrganizationsClient; -import com.dtsx.astra.sdk.organizations.domain.Role; -import com.dtsx.astra.sdk.organizations.domain.User; -import com.dtsx.astra.sdk.utils.IdUtils; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * Utility class for command `role` - * - * @author Cedrick LUNVEN (@clunven) - */ -public class OperationIam { - - /** working with roles. */ - public static final String COMMAND_ROLE = "role"; - /** Column name. */ - private static final String COLUMN_ROLE_ID = "Role Id"; - /** Column name. */ - private static final String COLUMN_ROLE_NAME = "Role Name"; - /** Column name. */ - private static final String COLUMN_ROLE_DESCRIPTION = "Description"; - - /** Column name. */ - private static final String COLUMN_USER_ID = "User Id"; - /** Column name. */ - private static final String COLUMN_USER_EMAIL = "User Email"; - /** Column name. */ - private static final String COLUMN_USER_STATUS = "Status"; - - /** - * Hide default constructor. - */ - private OperationIam() {} - - /** - * List Roles. - */ - public static void listRoles() { - ShellTable sht = new ShellTable(); - sht.addColumn(COLUMN_ROLE_ID, 37); - sht.addColumn(COLUMN_ROLE_NAME, 20); - sht.addColumn(COLUMN_ROLE_DESCRIPTION, 20); - CliContext.getInstance() - .getApiDevopsOrganizations() - .roles() - .forEach(role -> { - Map rf = new HashMap<>(); - rf.put(COLUMN_ROLE_ID, role.getId()); - rf.put(COLUMN_ROLE_NAME, role.getName()); - rf.put(COLUMN_ROLE_DESCRIPTION, role.getPolicy().getDescription()); - sht.getCellValues().add(rf); - }); - AstraCliConsole.printShellTable(sht); - } - - /** - * List Roles. - */ - public static void listUsers() { - ShellTable sht = new ShellTable(); - sht.addColumn(COLUMN_USER_ID, 37); - sht.addColumn(COLUMN_USER_EMAIL, 20); - sht.addColumn(COLUMN_USER_STATUS, 20); - CliContext.getInstance() - .getApiDevopsOrganizations() - .users().forEach(user -> { - Map rf = new HashMap<>(); - rf.put(COLUMN_USER_ID, user.getUserId()); - rf.put(COLUMN_USER_EMAIL, user.getEmail()); - rf.put(COLUMN_USER_STATUS, user.getStatus().name()); - sht.getCellValues().add(rf); - }); - AstraCliConsole.printShellTable(sht); - } - - /** - * Show Role details. - * - * @param role - * role name - * @throws RoleNotFoundException - * role has not been found - */ - public static void showRole(String role) throws RoleNotFoundException { - Optional optRole = CliContext - .getInstance() - .getApiDevopsOrganizations() - .findRoleByName(role); - - if (optRole.isEmpty() && IdUtils.isUUID(role)) { - optRole = CliContext - .getInstance() - .getApiDevopsOrganizations() - .role(role) - .find(); - } - - if (optRole.isEmpty()) { - throw new RoleNotFoundException(role); - } - - Role r = optRole.get(); - ShellTable sht = ShellTable.propertyTable(15, 40); - sht.addPropertyRow("Identifier", r.getId()); - sht.addPropertyRow("Name", r.getName()); - sht.addPropertyRow(COLUMN_ROLE_DESCRIPTION, r.getPolicy().getDescription()); - sht.addPropertyRow("Effect", r.getPolicy().getEffect()); - switch (CliContext.getInstance().getOutputFormat()) { - case CSV -> { - sht.addPropertyRow("Resources", r.getPolicy().getResources().toString()); - sht.addPropertyRow("Actions", r.getPolicy().getActions().toString()); - AstraCliConsole.printShellTable(sht); - } - case JSON -> AstraCliConsole.printJson(new JsonOutput<>(ExitCode.SUCCESS, - OperationIam.COMMAND_ROLE + " get " + role, r)); - case HUMAN -> { - sht.addPropertyListRows("Resources", r.getPolicy().getResources()); - sht.addPropertyListRows("Actions", r.getPolicy().getActions()); - AstraCliConsole.printShellTable(sht); - } - } - } - - /** - * Show User details. - * - * @param user - * user email - * @throws UserNotFoundException - * user has not been found - */ - public static void showUser(String user) throws UserNotFoundException { - Optional optUser = CliContext - .getInstance() - .getApiDevopsOrganizations() - .findUserByEmail(user); - - if (optUser.isEmpty() && IdUtils.isUUID(user)) { - optUser = CliContext - .getInstance() - .getApiDevopsOrganizations() - .user(user) - .find(); - } - - if (optUser.isEmpty()) { - throw new UserNotFoundException(user); - } - - User r = optUser.get(); - ShellTable sht = ShellTable.propertyTable(15, 40); - sht.addPropertyRow(COLUMN_USER_ID, r.getUserId()); - sht.addPropertyRow(COLUMN_USER_EMAIL, r.getEmail()); - sht.addPropertyRow(COLUMN_USER_STATUS, r.getStatus().name()); - - List roleNames = r.getRoles() - .stream() - .map(Role::getName) - .toList(); - - switch (CliContext.getInstance().getOutputFormat()) { - case CSV -> { - sht.addPropertyRow("Roles", roleNames.toString()); - AstraCliConsole.printShellTable(sht); - } - case JSON -> AstraCliConsole.printJson(new JsonOutput<>(ExitCode.SUCCESS, "user show " + user, r)); - case HUMAN -> { - sht.addPropertyListRows("Roles", roleNames); - AstraCliConsole.printShellTable(sht); - } - } - } - - /** - * Invite User. - * - * @param user - * user email - * @param role - * target role for the user - * @throws UserAlreadyExistException - * user does not exist - * @throws RoleNotFoundException - * role does not exist - */ - public static void inviteUser(String user, String role) throws UserAlreadyExistException, RoleNotFoundException { - OrganizationsClient oc = CliContext.getInstance().getApiDevopsOrganizations(); - Optional optUser = oc.findUserByEmail(user); - if (optUser.isPresent()) { - throw new UserAlreadyExistException(user); - } - Optional optRole = oc.findRoleByName(role); - if (optRole.isEmpty() && IdUtils.isUUID(role)) { - optRole = oc.role(role).find(); - } - if (optRole.isEmpty()) { - throw new RoleNotFoundException(role); - } - oc.inviteUser(user, optRole.get().getId()); - AstraCliConsole.outputSuccess(role); - } - - /** - * Delete a user if exist. - * @param user - * user email of technical identifier - * @throws UserNotFoundException - * user not found - */ - public static void deleteUser(String user) - throws UserNotFoundException { - OrganizationsClient oc = CliContext.getInstance().getApiDevopsOrganizations(); - Optional optUser = oc.findUserByEmail(user); - if (optUser.isEmpty() && IdUtils.isUUID(user)) { - optUser = oc.user(user).find(); - } - if (optUser.isEmpty()) { - throw new UserNotFoundException(user); - } - oc.user(optUser.get().getUserId()).delete(); - AstraCliConsole.outputSuccess("Deleting user '" + user + "' (async operation)"); - } - -} diff --git a/src/main/java/com/dtsx/astra/cli/db/DbGraphqlPlaygroundCmd.java b/src/main/java/com/dtsx/astra/cli/iam/role/AstraToken.java similarity index 69% rename from src/main/java/com/dtsx/astra/cli/db/DbGraphqlPlaygroundCmd.java rename to src/main/java/com/dtsx/astra/cli/iam/role/AstraToken.java index 72a75fa..b85d449 100644 --- a/src/main/java/com/dtsx/astra/cli/db/DbGraphqlPlaygroundCmd.java +++ b/src/main/java/com/dtsx/astra/cli/iam/role/AstraToken.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.db; +package com.dtsx.astra.cli.iam.role; /*- * #%L @@ -20,12 +20,15 @@ * #L% */ -public class DbGraphqlPlaygroundCmd { - - // ... -//Desktop. -//if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { - // Desktop.getDesktop().browse(new URI("http://www.example.com")); - // } - +/** + * Record for Astra Token. + * + * @param clientId + * client identifier + * @param clientSecret + * client secret + * @param token + * client token + */ +public record AstraToken(String clientId, String clientSecret, String token) { } diff --git a/src/main/java/com/dtsx/astra/cli/iam/RoleGetCmd.java b/src/main/java/com/dtsx/astra/cli/iam/role/RoleGetCmd.java similarity index 89% rename from src/main/java/com/dtsx/astra/cli/iam/RoleGetCmd.java rename to src/main/java/com/dtsx/astra/cli/iam/role/RoleGetCmd.java index b033112..577fbdd 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/RoleGetCmd.java +++ b/src/main/java/com/dtsx/astra/cli/iam/role/RoleGetCmd.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam; +package com.dtsx.astra.cli.iam.role; /*- * #%L @@ -21,7 +21,7 @@ */ import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.dtsx.astra.cli.iam.exception.RoleNotFoundException; +import com.dtsx.astra.cli.iam.role.exception.RoleNotFoundException; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.restrictions.Required; @@ -41,7 +41,7 @@ public class RoleGetCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() throws RoleNotFoundException { - OperationIam.showRole(role); + ServiceRole.getInstance().showRole(role); } } diff --git a/src/main/java/com/dtsx/astra/cli/iam/RoleListCmd.java b/src/main/java/com/dtsx/astra/cli/iam/role/RoleListCmd.java similarity index 92% rename from src/main/java/com/dtsx/astra/cli/iam/RoleListCmd.java rename to src/main/java/com/dtsx/astra/cli/iam/role/RoleListCmd.java index 5fe591b..6f9cc71 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/RoleListCmd.java +++ b/src/main/java/com/dtsx/astra/cli/iam/role/RoleListCmd.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam; +package com.dtsx.astra.cli.iam.role; /*- * #%L @@ -33,7 +33,7 @@ public class RoleListCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OperationIam.listRoles(); + ServiceRole.getInstance().listRoles(); } } diff --git a/src/main/java/com/dtsx/astra/cli/iam/role/ServiceRole.java b/src/main/java/com/dtsx/astra/cli/iam/role/ServiceRole.java new file mode 100644 index 0000000..1b99dae --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/iam/role/ServiceRole.java @@ -0,0 +1,161 @@ +package com.dtsx.astra.cli.iam.role; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.CliContext; +import com.dtsx.astra.cli.core.ExitCode; +import com.dtsx.astra.cli.core.out.AstraCliConsole; +import com.dtsx.astra.cli.core.out.JsonOutput; +import com.dtsx.astra.cli.core.out.ShellTable; +import com.dtsx.astra.cli.iam.role.exception.RoleNotFoundException; +import com.dtsx.astra.sdk.org.OrganizationsClient; +import com.dtsx.astra.sdk.org.domain.Role; +import com.dtsx.astra.sdk.utils.IdUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * Hold services to interact with Roles + */ +public class ServiceRole { + + /** Column name. */ + private static final String COLUMN_ROLE_ID = "Role Id"; + /** Column name. */ + private static final String COLUMN_ROLE_NAME = "Role Name"; + /** Column name. */ + private static final String COLUMN_ROLE_DESCRIPTION = "Description"; + + /** + * Singleton Pattern + */ + private static ServiceRole instance; + + /** + * Singleton Pattern. + * + * @return + * instance of the service. + */ + public static synchronized ServiceRole getInstance() { + if (null == instance) { + instance = new ServiceRole(); + } + return instance; + } + + /** + * Default Constructor. + */ + private ServiceRole() { + } + + /** + * Access Api devops from context. + * + * @return + * api devops + */ + private OrganizationsClient apiDevopsOrg() { + return CliContext.getInstance().getApiDevopsOrganizations(); + } + + /** + * List Roles. + */ + public void listRoles() { + ShellTable sht = new ShellTable(); + sht.addColumn(COLUMN_ROLE_ID, 37); + sht.addColumn(COLUMN_ROLE_NAME, 20); + sht.addColumn(COLUMN_ROLE_DESCRIPTION, 20); + apiDevopsOrg().roles().forEach(role -> { + Map rf = new HashMap<>(); + rf.put(COLUMN_ROLE_ID, role.getId()); + rf.put(COLUMN_ROLE_NAME, role.getName()); + rf.put(COLUMN_ROLE_DESCRIPTION, role.getPolicy().getDescription()); + sht.getCellValues().add(rf); + }); + AstraCliConsole.printShellTable(sht); + } + + /** + * Will find the role or empty. + * + * @param role + * current role identifier + * @return + * role value + */ + public Optional findRole(String role) { + // Find with name + Optional optRole = apiDevopsOrg().findRoleByName(role); + // Find by id if not found by name + if (optRole.isEmpty() && IdUtils.isUUID(role)) { + optRole = apiDevopsOrg().role(role).find(); + } + return optRole; + } + + /** + * Get value of a role for sure. + * + * @param role + * current role + * @return + * value for role + */ + public Role get(String role) { + return findRole(role).orElseThrow(() -> new RoleNotFoundException(role)); + } + + /** + * Show Role details. + * + * @param role + * role name + * @throws RoleNotFoundException + * role has not been found + */ + public void showRole(String role) throws RoleNotFoundException { + Role r = get(role); + ShellTable sht = ShellTable.propertyTable(15, 40); + sht.addPropertyRow("Identifier", r.getId()); + sht.addPropertyRow("Name", r.getName()); + sht.addPropertyRow(COLUMN_ROLE_DESCRIPTION, r.getPolicy().getDescription()); + sht.addPropertyRow("Effect", r.getPolicy().getEffect()); + switch (CliContext.getInstance().getOutputFormat()) { + case CSV -> { + sht.addPropertyRow("Resources", r.getPolicy().getResources().toString()); + sht.addPropertyRow("Actions", r.getPolicy().getActions().toString()); + AstraCliConsole.printShellTable(sht); + } + case JSON -> + AstraCliConsole.printJson(new JsonOutput<>(ExitCode.SUCCESS, "role get " + role, r)); + case HUMAN -> { + sht.addPropertyListRows("Resources", r.getPolicy().getResources()); + sht.addPropertyListRows("Actions", r.getPolicy().getActions()); + AstraCliConsole.printShellTable(sht); + } + } + } +} diff --git a/src/main/java/com/dtsx/astra/cli/iam/exception/RoleNotFoundException.java b/src/main/java/com/dtsx/astra/cli/iam/role/exception/RoleNotFoundException.java similarity index 96% rename from src/main/java/com/dtsx/astra/cli/iam/exception/RoleNotFoundException.java rename to src/main/java/com/dtsx/astra/cli/iam/role/exception/RoleNotFoundException.java index 96841c1..89d445e 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/exception/RoleNotFoundException.java +++ b/src/main/java/com/dtsx/astra/cli/iam/role/exception/RoleNotFoundException.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam.exception; +package com.dtsx.astra.cli.iam.role.exception; /*- * #%L diff --git a/src/main/java/com/dtsx/astra/cli/iam/token/ServiceToken.java b/src/main/java/com/dtsx/astra/cli/iam/token/ServiceToken.java new file mode 100644 index 0000000..5ae2367 --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/iam/token/ServiceToken.java @@ -0,0 +1,185 @@ +package com.dtsx.astra.cli.iam.token; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.CliContext; +import com.dtsx.astra.cli.core.exception.TokenNotFoundException; +import com.dtsx.astra.cli.core.out.AstraCliConsole; +import com.dtsx.astra.cli.core.out.LoggerShell; +import com.dtsx.astra.cli.core.out.ShellTable; +import com.dtsx.astra.cli.iam.role.AstraToken; +import com.dtsx.astra.cli.iam.role.ServiceRole; +import com.dtsx.astra.sdk.org.OrganizationsClient; +import com.dtsx.astra.sdk.org.domain.CreateTokenResponse; +import com.dtsx.astra.sdk.org.domain.IamToken; +import com.dtsx.astra.sdk.org.domain.Role; +import com.dtsx.astra.sdk.org.iam.TokenClient; +import com.dtsx.astra.sdk.utils.Assert; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * Work with token. + */ +public class ServiceToken { + + /** column names. */ + public static final String COL_CLIENT_ID = "Client Id"; + + /** column names. */ + public static final String COL_CLIENT_SECRET = "Client Secret"; + + /** column names. */ + public static final String COL_CLIENT_TOKEN = "Token"; + + /** column names. */ + public static final String COL_ROLES = "Role"; + + /** column names. */ + public static final String COL_GENERATED_ON = "Generated On"; + + /** + * Singleton Pattern + */ + private static ServiceToken instance; + + /** + * Default Constructor. + */ + private ServiceToken() { + } + + /** + * Singleton Pattern. + * + * @return + * instance of the service. + */ + public static synchronized ServiceToken getInstance() { + if (null == instance) { + instance = new ServiceToken(); + } + return instance; + } + + /** + * Access Api devops from context. + * + * @return + * api devops + */ + private OrganizationsClient apiDevopsOrg() { + return CliContext.getInstance().getApiDevopsOrganizations(); + } + + /** + * Find a token by its id. + * + * @param clientId + * client identifier. + * @return + * token when exist + */ + public Optional findToken(String clientId) { + return apiDevopsOrg().tokens() + .filter(t -> t.getClientId().equals(clientId)) + .findFirst(); + } + + /** + * Find a token by its id. + * + * @param clientId + * client identifier. + * @return + * true if token exists + */ + public boolean tokenExist(String clientId) { + return findToken(clientId).isPresent(); + } + + /** + * List tokens of an organization. + */ + public void listTokens() { + ShellTable sht = new ShellTable(); + sht.addColumn(COL_GENERATED_ON, 15); + sht.addColumn(COL_CLIENT_ID, 20); + sht.addColumn(COL_ROLES, 30); + apiDevopsOrg().tokens().forEach(tok -> { + Map currentLine = new HashMap<>(); + currentLine.put(COL_GENERATED_ON, tok.getGeneratedOn()); + currentLine.put(COL_CLIENT_ID, tok.getClientId()); + currentLine.put(COL_ROLES, tok.getRoles().get(0)); + sht.getCellValues().add(currentLine); + // Add multiple lines for a single token if multiple Roles + if (tok.getRoles().size() > 1) { + for(int i=1;i< tok.getRoles().size();i++) { + Map line = new HashMap<>(); + line.put(COL_GENERATED_ON, ""); + line.put(COL_CLIENT_ID, ""); + line.put(COL_ROLES, tok.getRoles().get(i)); + sht.getCellValues().add(line); + } + } + }); + AstraCliConsole.printShellTable(sht); + } + + /** + * Create a new token with a role. + * + * @param role + * role asked + */ + public AstraToken createToken(String role) { + // Validate that role exists. + Assert.hasLength(role, "role"); + Role r = ServiceRole.getInstance().get(role); + CreateTokenResponse iam = apiDevopsOrg().createToken(r.getId()); + LoggerShell.success("A new token has been created."); + AstraToken astraToken = new AstraToken(iam.getClientId(), iam.getSecret(), iam.getToken()); + // Display Created token as a table + ShellTable sht = ShellTable.propertyTable(15, 40); + sht.addPropertyRow(COL_CLIENT_ID, astraToken.clientId()); + sht.addPropertyRow(COL_CLIENT_SECRET, astraToken.clientSecret()); + sht.addPropertyRow(COL_CLIENT_TOKEN, astraToken.token()); + AstraCliConsole.printShellTable(sht); + return astraToken; + } + + /** + * Delete a token from its id. + * + * @param tokenId + * token identifier + */ + public void deleteToken(String tokenId) { + Assert.hasLength(tokenId, "tokenId"); + TokenClient tokenClient = apiDevopsOrg().token(tokenId); + tokenClient.find().orElseThrow(() -> new TokenNotFoundException(tokenId)); + tokenClient.delete(); + LoggerShell.success("Your token has been deleted."); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/iam/token/TokenCreateCmd.java b/src/main/java/com/dtsx/astra/cli/iam/token/TokenCreateCmd.java new file mode 100644 index 0000000..99befcb --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/iam/token/TokenCreateCmd.java @@ -0,0 +1,44 @@ +package com.dtsx.astra.cli.iam.token; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.AbstractConnectedCmd; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.Option; +import com.github.rvesse.airline.annotations.restrictions.Required; + +@Command(name = "create", description = "Display the list of tokens in an organization") +public class TokenCreateCmd extends AbstractConnectedCmd { + + /** Provide a keyspace Name. */ + @Required + @Option(name = {"-r", "--role" }, + title = "ROLE", + arity = 1, + description = "Identifier of the role for this token") + public String role; + + /** {@inheritDoc} */ + public void execute() { + ServiceToken.getInstance().createToken(role); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/iam/token/TokenDeleteCmd.java b/src/main/java/com/dtsx/astra/cli/iam/token/TokenDeleteCmd.java new file mode 100644 index 0000000..a5a732b --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/iam/token/TokenDeleteCmd.java @@ -0,0 +1,41 @@ +package com.dtsx.astra.cli.iam.token; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.AbstractConnectedCmd; +import com.github.rvesse.airline.annotations.Arguments; +import com.github.rvesse.airline.annotations.Command; +import com.github.rvesse.airline.annotations.restrictions.Required; + +@Command(name = "delete", description = "Delete a token") +public class TokenDeleteCmd extends AbstractConnectedCmd { + + /** Role name or id. */ + @Required + @Arguments(title = "TOKEN", description = "token identifier") + protected String inputToken; + + /** {@inheritDoc} */ + public void execute() { + ServiceToken.getInstance().deleteToken(inputToken); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/iam/token/TokenListCmd.java b/src/main/java/com/dtsx/astra/cli/iam/token/TokenListCmd.java new file mode 100644 index 0000000..17df005 --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/iam/token/TokenListCmd.java @@ -0,0 +1,34 @@ +package com.dtsx.astra.cli.iam.token; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.AbstractConnectedCmd; +import com.github.rvesse.airline.annotations.Command; + +@Command(name = "list", description = "Display the list of tokens in an organization") +public class TokenListCmd extends AbstractConnectedCmd { + + /** {@inheritDoc} */ + public void execute() { + ServiceToken.getInstance().listTokens(); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/iam/user/ServiceUser.java b/src/main/java/com/dtsx/astra/cli/iam/user/ServiceUser.java new file mode 100644 index 0000000..fa066a9 --- /dev/null +++ b/src/main/java/com/dtsx/astra/cli/iam/user/ServiceUser.java @@ -0,0 +1,189 @@ +package com.dtsx.astra.cli.iam.user; + +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.cli.core.CliContext; +import com.dtsx.astra.cli.core.ExitCode; +import com.dtsx.astra.cli.core.out.AstraCliConsole; +import com.dtsx.astra.cli.core.out.JsonOutput; +import com.dtsx.astra.cli.core.out.ShellTable; +import com.dtsx.astra.cli.iam.role.exception.RoleNotFoundException; +import com.dtsx.astra.cli.iam.user.exception.UserAlreadyExistException; +import com.dtsx.astra.cli.iam.user.exception.UserNotFoundException; +import com.dtsx.astra.sdk.org.OrganizationsClient; +import com.dtsx.astra.sdk.org.domain.Role; +import com.dtsx.astra.sdk.org.domain.User; +import com.dtsx.astra.sdk.utils.IdUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * Utility class for command `role` + * + * @author Cedrick LUNVEN (@clunven) + */ +public class ServiceUser { + + /** Column name. */ + private static final String COLUMN_USER_ID = "User Id"; + /** Column name. */ + private static final String COLUMN_USER_EMAIL = "User Email"; + /** Column name. */ + private static final String COLUMN_USER_STATUS = "Status"; + + /** + * Singleton Pattern + */ + private static ServiceUser instance; + + /** + * Singleton Pattern. + * + * @return + * instance of the service. + */ + public static synchronized ServiceUser getInstance() { + if (null == instance) { + instance = new ServiceUser(); + } + return instance; + } + + /** + * Default Constructor. + */ + private ServiceUser() {} + + /** + * Access Api devops from context. + * + * @return + * api devops + */ + private OrganizationsClient apiDevopsOrg() { + return CliContext.getInstance().getApiDevopsOrganizations(); + } + + /** + * List Roles. + */ + public void listUsers() { + ShellTable sht = new ShellTable(); + sht.addColumn(COLUMN_USER_ID, 37); + sht.addColumn(COLUMN_USER_EMAIL, 20); + sht.addColumn(COLUMN_USER_STATUS, 20); + apiDevopsOrg().users().forEach(user -> { + Map rf = new HashMap<>(); + rf.put(COLUMN_USER_ID, user.getUserId()); + rf.put(COLUMN_USER_EMAIL, user.getEmail()); + rf.put(COLUMN_USER_STATUS, user.getStatus().name()); + sht.getCellValues().add(rf); + }); + AstraCliConsole.printShellTable(sht); + } + + /** + * Show User details. + * + * @param user + * user email + * @throws UserNotFoundException + * user has not been found + */ + public void showUser(String user) throws UserNotFoundException { + Optional optUser = apiDevopsOrg().findUserByEmail(user); + + if (optUser.isEmpty() && IdUtils.isUUID(user)) { + optUser = apiDevopsOrg().user(user).find(); + } + + User r = optUser.orElseThrow(() -> new UserNotFoundException(user)); + ShellTable sht = ShellTable.propertyTable(15, 40); + sht.addPropertyRow(COLUMN_USER_ID, r.getUserId()); + sht.addPropertyRow(COLUMN_USER_EMAIL, r.getEmail()); + sht.addPropertyRow(COLUMN_USER_STATUS, r.getStatus().name()); + + List roleNames = r.getRoles() + .stream() + .map(Role::getName) + .toList(); + + switch (CliContext.getInstance().getOutputFormat()) { + case CSV -> { + sht.addPropertyRow("Roles", roleNames.toString()); + AstraCliConsole.printShellTable(sht); + } + case JSON -> + AstraCliConsole.printJson(new JsonOutput<>(ExitCode.SUCCESS, "user show " + user, r)); + case HUMAN -> { + sht.addPropertyListRows("Roles", roleNames); + AstraCliConsole.printShellTable(sht); + } + } + } + + /** + * Invite User. + * + * @param user + * user email + * @param role + * target role for the user + * @throws UserAlreadyExistException + * user does not exist + * @throws RoleNotFoundException + * role does not exist + */ + public void inviteUser(String user, String role) throws UserAlreadyExistException, RoleNotFoundException { + Optional optUser = apiDevopsOrg().findUserByEmail(user); + if (optUser.isPresent()) { + throw new UserAlreadyExistException(user); + } + Optional optRole = apiDevopsOrg().findRoleByName(role); + if (optRole.isEmpty() && IdUtils.isUUID(role)) { + optRole = apiDevopsOrg().role(role).find(); + } + apiDevopsOrg().inviteUser(user, optRole.orElseThrow(()-> new RoleNotFoundException(role)).getId()); + AstraCliConsole.outputSuccess(role); + } + + /** + * Delete a user if exist. + * @param user + * user email of technical identifier + * @throws UserNotFoundException + * user not found + */ + public void deleteUser(String user) + throws UserNotFoundException { + Optional optUser = apiDevopsOrg().findUserByEmail(user); + if (optUser.isEmpty() && IdUtils.isUUID(user)) { + optUser = apiDevopsOrg().user(user).find(); + } + apiDevopsOrg().user(optUser.orElseThrow(() -> new UserNotFoundException(user)).getUserId()) + .delete(); + AstraCliConsole.outputSuccess("Deleting user '" + user + "' (async operation)"); + } + +} diff --git a/src/main/java/com/dtsx/astra/cli/iam/UserDeleteCmd.java b/src/main/java/com/dtsx/astra/cli/iam/user/UserDeleteCmd.java similarity index 89% rename from src/main/java/com/dtsx/astra/cli/iam/UserDeleteCmd.java rename to src/main/java/com/dtsx/astra/cli/iam/user/UserDeleteCmd.java index e3555e1..1f01832 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/UserDeleteCmd.java +++ b/src/main/java/com/dtsx/astra/cli/iam/user/UserDeleteCmd.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam; +package com.dtsx.astra.cli.iam.user; /*- * #%L @@ -21,7 +21,7 @@ */ import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.dtsx.astra.cli.iam.exception.UserNotFoundException; +import com.dtsx.astra.cli.iam.user.exception.UserNotFoundException; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.restrictions.Required; @@ -43,7 +43,7 @@ public class UserDeleteCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() throws UserNotFoundException { - OperationIam.deleteUser(user); + ServiceUser.getInstance().deleteUser(user); } } diff --git a/src/main/java/com/dtsx/astra/cli/iam/UserGetCmd.java b/src/main/java/com/dtsx/astra/cli/iam/user/UserGetCmd.java similarity index 89% rename from src/main/java/com/dtsx/astra/cli/iam/UserGetCmd.java rename to src/main/java/com/dtsx/astra/cli/iam/user/UserGetCmd.java index fe8942c..b0ba43f 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/UserGetCmd.java +++ b/src/main/java/com/dtsx/astra/cli/iam/user/UserGetCmd.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam; +package com.dtsx.astra.cli.iam.user; /*- * #%L @@ -21,7 +21,7 @@ */ import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.dtsx.astra.cli.iam.exception.UserNotFoundException; +import com.dtsx.astra.cli.iam.user.exception.UserNotFoundException; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.restrictions.Required; @@ -41,7 +41,7 @@ public class UserGetCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() throws UserNotFoundException { - OperationIam.showUser(user); + ServiceUser.getInstance().showUser(user); } } diff --git a/src/main/java/com/dtsx/astra/cli/iam/UserInviteCmd.java b/src/main/java/com/dtsx/astra/cli/iam/user/UserInviteCmd.java similarity index 85% rename from src/main/java/com/dtsx/astra/cli/iam/UserInviteCmd.java rename to src/main/java/com/dtsx/astra/cli/iam/user/UserInviteCmd.java index 2812557..7cbfb70 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/UserInviteCmd.java +++ b/src/main/java/com/dtsx/astra/cli/iam/user/UserInviteCmd.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam; +package com.dtsx.astra.cli.iam.user; /*- * #%L @@ -21,9 +21,9 @@ */ import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.dtsx.astra.cli.iam.exception.RoleNotFoundException; -import com.dtsx.astra.cli.iam.exception.UserAlreadyExistException; -import com.dtsx.astra.sdk.organizations.domain.DefaultRoles; +import com.dtsx.astra.cli.iam.role.exception.RoleNotFoundException; +import com.dtsx.astra.cli.iam.user.exception.UserAlreadyExistException; +import com.dtsx.astra.sdk.org.domain.DefaultRoles; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; @@ -52,7 +52,7 @@ public class UserInviteCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ @Override public void execute() throws UserAlreadyExistException, RoleNotFoundException { - OperationIam.inviteUser(user, role); + ServiceUser.getInstance().inviteUser(user, role); } } diff --git a/src/main/java/com/dtsx/astra/cli/iam/UserListCmd.java b/src/main/java/com/dtsx/astra/cli/iam/user/UserListCmd.java similarity index 92% rename from src/main/java/com/dtsx/astra/cli/iam/UserListCmd.java rename to src/main/java/com/dtsx/astra/cli/iam/user/UserListCmd.java index 88d2df5..0861257 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/UserListCmd.java +++ b/src/main/java/com/dtsx/astra/cli/iam/user/UserListCmd.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam; +package com.dtsx.astra.cli.iam.user; /*- * #%L @@ -33,7 +33,7 @@ public class UserListCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OperationIam.listUsers(); + ServiceUser.getInstance().listUsers(); } } diff --git a/src/main/java/com/dtsx/astra/cli/iam/exception/UserAlreadyExistException.java b/src/main/java/com/dtsx/astra/cli/iam/user/exception/UserAlreadyExistException.java similarity index 96% rename from src/main/java/com/dtsx/astra/cli/iam/exception/UserAlreadyExistException.java rename to src/main/java/com/dtsx/astra/cli/iam/user/exception/UserAlreadyExistException.java index a80297c..338fdbb 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/exception/UserAlreadyExistException.java +++ b/src/main/java/com/dtsx/astra/cli/iam/user/exception/UserAlreadyExistException.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam.exception; +package com.dtsx.astra.cli.iam.user.exception; /*- * #%L diff --git a/src/main/java/com/dtsx/astra/cli/iam/exception/UserNotFoundException.java b/src/main/java/com/dtsx/astra/cli/iam/user/exception/UserNotFoundException.java similarity index 96% rename from src/main/java/com/dtsx/astra/cli/iam/exception/UserNotFoundException.java rename to src/main/java/com/dtsx/astra/cli/iam/user/exception/UserNotFoundException.java index 694e64f..ea022e2 100644 --- a/src/main/java/com/dtsx/astra/cli/iam/exception/UserNotFoundException.java +++ b/src/main/java/com/dtsx/astra/cli/iam/user/exception/UserNotFoundException.java @@ -1,4 +1,4 @@ -package com.dtsx.astra.cli.iam.exception; +package com.dtsx.astra.cli.iam.user.exception; /*- * #%L diff --git a/src/main/java/com/dtsx/astra/cli/org/OrgCmd.java b/src/main/java/com/dtsx/astra/cli/org/OrgCmd.java index c1dd8e5..156c429 100644 --- a/src/main/java/com/dtsx/astra/cli/org/OrgCmd.java +++ b/src/main/java/com/dtsx/astra/cli/org/OrgCmd.java @@ -33,7 +33,7 @@ public class OrgCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OrganizationService.getInstance().showOrg(); + ServiceOrganization.getInstance().showOrg(); } } diff --git a/src/main/java/com/dtsx/astra/cli/org/OrgIdCmd.java b/src/main/java/com/dtsx/astra/cli/org/OrgIdCmd.java index 2a24ded..934c773 100644 --- a/src/main/java/com/dtsx/astra/cli/org/OrgIdCmd.java +++ b/src/main/java/com/dtsx/astra/cli/org/OrgIdCmd.java @@ -28,12 +28,12 @@ * * @author Cedrick LUNVEN (@clunven) */ -@Command(name = OrganizationService.CMD_ID, description = "Show organization id.") +@Command(name = ServiceOrganization.CMD_ID, description = "Show organization id.") public class OrgIdCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OrganizationService.getInstance().getId(); + ServiceOrganization.getInstance().getId(); } } diff --git a/src/main/java/com/dtsx/astra/cli/org/OrgNameCmd.java b/src/main/java/com/dtsx/astra/cli/org/OrgNameCmd.java index 32f5494..7842b58 100644 --- a/src/main/java/com/dtsx/astra/cli/org/OrgNameCmd.java +++ b/src/main/java/com/dtsx/astra/cli/org/OrgNameCmd.java @@ -28,12 +28,12 @@ * * @author Cedrick LUNVEN (@clunven) */ -@Command(name = OrganizationService.CMD_NAME, description = "Show organization name.") +@Command(name = ServiceOrganization.CMD_NAME, description = "Show organization name.") public class OrgNameCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OrganizationService.getInstance().getName(); + ServiceOrganization.getInstance().getName(); } } diff --git a/src/main/java/com/dtsx/astra/cli/org/OrganizationService.java b/src/main/java/com/dtsx/astra/cli/org/ServiceOrganization.java similarity index 84% rename from src/main/java/com/dtsx/astra/cli/org/OrganizationService.java rename to src/main/java/com/dtsx/astra/cli/org/ServiceOrganization.java index 120162e..088f4be 100644 --- a/src/main/java/com/dtsx/astra/cli/org/OrganizationService.java +++ b/src/main/java/com/dtsx/astra/cli/org/ServiceOrganization.java @@ -24,8 +24,8 @@ import com.dtsx.astra.cli.core.out.AstraCliConsole; import com.dtsx.astra.cli.core.out.LoggerShell; import com.dtsx.astra.cli.core.out.ShellTable; -import com.dtsx.astra.sdk.organizations.OrganizationsClient; -import com.dtsx.astra.sdk.organizations.domain.Organization; +import com.dtsx.astra.sdk.org.OrganizationsClient; +import com.dtsx.astra.sdk.org.domain.Organization; import java.util.*; @@ -34,15 +34,13 @@ * * @author Cedrick LUNVEN (@clunven) */ -public class OrganizationService { +public class ServiceOrganization { /** cmd. */ public static final String CMD_ID = "id"; /** cmd. */ public static final String CMD_NAME = "name"; - /** cmd. */ - public static final String CMD_REGIONS_STREAMING = "list-regions"; - /** column names. */ + /** column names. */ public static final String COLUMN_ID = "id"; /** column names. */ public static final String COLUMN_NAME = "Name"; @@ -53,13 +51,10 @@ public class OrganizationService { /** column names. */ public static final String COLUMN_REGION_DISPLAY= "Full Name"; - /** Http Client for devops Api. */ - private final OrganizationsClient orgClient; - /** * Singleton pattern. */ - private static OrganizationService instance; + private static ServiceOrganization instance; /** * Singleton pattern. @@ -67,85 +62,91 @@ public class OrganizationService { * @return * organization. */ - public static synchronized OrganizationService getInstance() { + public static synchronized ServiceOrganization getInstance() { if (instance == null) { - instance = new OrganizationService(CliContext.getInstance().getApiDevopsOrganizations()); + instance = new ServiceOrganization(); } return instance; } /** - * Hide default constructor. + * Access Api devops from context. * - * @param orgClient - * http client to organization + * @return + * api devops + */ + private OrganizationsClient apiDevopsOrg() { + return CliContext.getInstance().getApiDevopsOrganizations(); + } + + /** + * Hide default constructor. */ - private OrganizationService(OrganizationsClient orgClient) { - this.orgClient = orgClient; + private ServiceOrganization() { } /** * Return organization id. */ public void getId() { - LoggerShell.println(orgClient.organizationId()); + LoggerShell.println(apiDevopsOrg().organizationId()); } /** * Return organization name. */ public void getName() { - LoggerShell.println(orgClient.organization().getName()); + LoggerShell.println(apiDevopsOrg().organization().getName()); } /** * Return organization info. */ public void showOrg() { - Organization org = orgClient.organization(); + Organization org = apiDevopsOrg().organization(); ShellTable sht = ShellTable.propertyTable(15, 40); sht.addPropertyRow(COLUMN_NAME, org.getName()); sht.addPropertyRow(COLUMN_ID, org.getId()); AstraCliConsole.printShellTable(sht); } - + /** - * Show organization database classic regions. + * List streaming regions * * @param cloudProvider * name of cloud provider * @param filter * name of filter */ - public void listRegionsDbClassic(String cloudProvider, String filter) { - // Sorting Regions per cloud than region name + public void listRegionsStreaming(String cloudProvider, String filter) { TreeMap> sortedRegion = new TreeMap<>(); - orgClient.regions().forEach(r -> { - String cloud = r.getCloudProvider().toString().toLowerCase(); + CliContext.getInstance() + .getApiDevopsStreaming() + .serverlessRegions().forEach(r -> { + String cloud = r.getCloudProvider().toLowerCase(); sortedRegion.computeIfAbsent(cloud, k -> new TreeMap<>()); - sortedRegion.get(cloud).put(r.getRegion(), r.getRegionDisplay()); + sortedRegion.get(cloud).put(r.getName(), r.getDisplayName()); }); - // Building Table AstraCliConsole.printShellTable(buildShellTable(cloudProvider, filter, sortedRegion)); } /** - * List streaming regions + * Show organization database classic regions. * * @param cloudProvider * name of cloud provider * @param filter * name of filter */ - public void listRegionsStreaming(String cloudProvider, String filter) { + public void listRegionsDbClassic(String cloudProvider, String filter) { + // Sorting Regions per cloud than region name TreeMap> sortedRegion = new TreeMap<>(); - CliContext.getInstance() - .getApiDevopsStreaming() - .serverlessRegions().forEach(r -> { - String cloud = r.getCloudProvider().toLowerCase(); + apiDevopsOrg().regions().forEach(r -> { + String cloud = r.getCloudProvider().toString().toLowerCase(); sortedRegion.computeIfAbsent(cloud, k -> new TreeMap<>()); - sortedRegion.get(cloud).put(r.getName(), r.getDisplayName()); + sortedRegion.get(cloud).put(r.getRegion(), r.getRegionDisplay()); }); + // Building Table AstraCliConsole.printShellTable(buildShellTable(cloudProvider, filter, sortedRegion)); } @@ -159,7 +160,7 @@ public void listRegionsStreaming(String cloudProvider, String filter) { */ public void listRegionsDbServerless(String cloudProvider, String filter) { TreeMap> sortedRegion = new TreeMap<>(); - orgClient.regionsServerless().forEach(r -> { + apiDevopsOrg().regionsServerless().forEach(r -> { String cloud = r.getCloudProvider().toLowerCase(); sortedRegion.computeIfAbsent(cloud, k -> new TreeMap<>()); sortedRegion.get(cloud).put(r.getName(), r.getDisplayName()); diff --git a/src/main/java/com/dtsx/astra/cli/streaming/AbstractStreamingCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/AbstractStreamingCmd.java index a686df8..0b9a086 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/AbstractStreamingCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/AbstractStreamingCmd.java @@ -1,5 +1,25 @@ package com.dtsx.astra.cli.streaming; +/*- + * #%L + * Astra Cli + * %% + * Copyright (C) 2022 DataStax + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import com.dtsx.astra.cli.core.AbstractConnectedCmd; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.restrictions.Required; diff --git a/src/main/java/com/dtsx/astra/cli/streaming/OperationsStreaming.java b/src/main/java/com/dtsx/astra/cli/streaming/ServiceStreaming.java similarity index 99% rename from src/main/java/com/dtsx/astra/cli/streaming/OperationsStreaming.java rename to src/main/java/com/dtsx/astra/cli/streaming/ServiceStreaming.java index d13ccd5..c687926 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/OperationsStreaming.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/ServiceStreaming.java @@ -44,7 +44,7 @@ * * @author Cedrick LUNVEN (@clunven) */ -public class OperationsStreaming { +public class ServiceStreaming { /** Command constants. */ public static final String CMD_STATUS = "status"; @@ -81,7 +81,7 @@ public class OperationsStreaming { /** * Hide default constructor */ - private OperationsStreaming() {} + private ServiceStreaming() {} /** * Syntax Sugar to work with Streaming Devops Apis. diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingCreateCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingCreateCmd.java index d741208..0de1091 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingCreateCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingCreateCmd.java @@ -20,10 +20,10 @@ * #L% */ -import static com.dtsx.astra.cli.streaming.OperationsStreaming.DEFAULT_CLOUD_PROVIDER; -import static com.dtsx.astra.cli.streaming.OperationsStreaming.DEFAULT_CLOUD_REGION; -import static com.dtsx.astra.cli.streaming.OperationsStreaming.DEFAULT_CLOUD_TENANT; -import static com.dtsx.astra.cli.streaming.OperationsStreaming.DEFAULT_EMAIL; +import static com.dtsx.astra.cli.streaming.ServiceStreaming.DEFAULT_CLOUD_PROVIDER; +import static com.dtsx.astra.cli.streaming.ServiceStreaming.DEFAULT_CLOUD_REGION; +import static com.dtsx.astra.cli.streaming.ServiceStreaming.DEFAULT_CLOUD_TENANT; +import static com.dtsx.astra.cli.streaming.ServiceStreaming.DEFAULT_EMAIL; import com.dtsx.astra.cli.core.AbstractConnectedCmd; import com.dtsx.astra.sdk.streaming.domain.CreateTenant; @@ -80,7 +80,7 @@ public void execute() { // Param Validations //throw new ParameterException(cloudProvider) // Does the tenant exist ? - OperationsStreaming.createStreamingTenant(ct); + ServiceStreaming.createStreamingTenant(ct); } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingCreateDotEnvCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingCreateDotEnvCmd.java index 1383372..4f82d3f 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingCreateDotEnvCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingCreateDotEnvCmd.java @@ -45,6 +45,6 @@ public class StreamingCreateDotEnvCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OperationsStreaming.generateDotEnvFile(tenant, destination); + ServiceStreaming.generateDotEnvFile(tenant, destination); } } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingDeleteCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingDeleteCmd.java index 94aa5bb..adde1e1 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingDeleteCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingDeleteCmd.java @@ -20,11 +20,8 @@ * #L% */ -import com.dtsx.astra.cli.core.AbstractConnectedCmd; import com.dtsx.astra.cli.streaming.exception.TenantNotFoundException; -import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; -import com.github.rvesse.airline.annotations.restrictions.Required; /** * Delete a tenant if exists @@ -37,7 +34,7 @@ public class StreamingDeleteCmd extends AbstractStreamingCmd { /** {@inheritDoc} */ public void execute() throws TenantNotFoundException { - OperationsStreaming.deleteTenant(tenant); + ServiceStreaming.deleteTenant(tenant); } } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingExistCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingExistCmd.java index 2ade639..0d6a869 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingExistCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingExistCmd.java @@ -20,22 +20,19 @@ * #L% */ -import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; -import com.github.rvesse.airline.annotations.restrictions.Required; /** * Display information relative to a tenant. * * @author Cedrick LUNVEN (@clunven) */ -@Command(name = OperationsStreaming.CMD_EXIST, description = "Show existence of a tenant") +@Command(name = ServiceStreaming.CMD_EXIST, description = "Show existence of a tenant") public class StreamingExistCmd extends AbstractStreamingCmd { /** {@inheritDoc} */ public void execute() { - OperationsStreaming.showTenantExistence(tenant); + ServiceStreaming.showTenantExistence(tenant); } } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingGetCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingGetCmd.java index d09fae8..23ccf02 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingGetCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingGetCmd.java @@ -103,7 +103,7 @@ public void execute() .toString())); } } - OperationsStreaming.showTenant(tenant, sKey); + ServiceStreaming.showTenant(tenant, sKey); } } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingListCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingListCmd.java index cab8d10..0d36531 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingListCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingListCmd.java @@ -33,7 +33,7 @@ public class StreamingListCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OperationsStreaming.listTenants(); + ServiceStreaming.listTenants(); } } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingListRegionsCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingListRegionsCmd.java index 36229e8..5ccb7ce 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingListRegionsCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingListRegionsCmd.java @@ -21,7 +21,7 @@ */ import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.dtsx.astra.cli.org.OrganizationService; +import com.dtsx.astra.cli.org.ServiceOrganization; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; @@ -47,6 +47,6 @@ public class StreamingListRegionsCmd extends AbstractConnectedCmd { /** {@inheritDoc} */ public void execute() { - OrganizationService.getInstance().listRegionsStreaming(cloud, filter); + ServiceOrganization.getInstance().listRegionsStreaming(cloud, filter); } } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingPulsarTokenCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingPulsarTokenCmd.java index 5e87b47..e5ddb07 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingPulsarTokenCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingPulsarTokenCmd.java @@ -28,13 +28,13 @@ * * @author Cedrick LUNVEN (@clunven) */ -@Command(name = OperationsStreaming.CMD_GET_TOKEN, description = "Show status of a tenant") +@Command(name = ServiceStreaming.CMD_GET_TOKEN, description = "Show status of a tenant") public class StreamingPulsarTokenCmd extends AbstractStreamingCmd { /** {@inheritDoc} */ public void execute() throws TenantNotFoundException { - OperationsStreaming.showTenantPulsarToken(tenant); + ServiceStreaming.showTenantPulsarToken(tenant); } } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/StreamingStatusCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/StreamingStatusCmd.java index 6b7553d..ad0d75f 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/StreamingStatusCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/StreamingStatusCmd.java @@ -28,13 +28,13 @@ * * @author Cedrick LUNVEN (@clunven) */ -@Command(name = OperationsStreaming.CMD_STATUS, description = "Show status of a tenant") +@Command(name = ServiceStreaming.CMD_STATUS, description = "Show status of a tenant") public class StreamingStatusCmd extends AbstractStreamingCmd { /** {@inheritDoc} */ public void execute() throws TenantNotFoundException { - OperationsStreaming.showTenantStatus(tenant); + ServiceStreaming.showTenantStatus(tenant); } } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingCreateCdcCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingCreateCdcCmd.java index 26ae103..17ff837 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingCreateCdcCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingCreateCdcCmd.java @@ -20,19 +20,12 @@ * #L% */ -import com.dtsx.astra.cli.core.AbstractConnectedCmd; -import com.dtsx.astra.cli.core.exception.InvalidArgumentException; import com.dtsx.astra.cli.streaming.AbstractStreamingCmd; -import com.dtsx.astra.cli.streaming.exception.TenantNotFoundException; -import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; import com.github.rvesse.airline.annotations.Option; -import com.github.rvesse.airline.annotations.restrictions.Required; - -import java.util.Arrays; /** - * Display information relative to a db. + * Declare a Change Data Capture between DB and Pulsar. * * @author Cedrick LUNVEN (@clunven) */ @@ -40,7 +33,7 @@ public class StreamingCreateCdcCmd extends AbstractStreamingCmd { /** Options. */ - @Option(name = {"-db", "--database" }, title = "DATABSE", arity = 1, + @Option(name = {"-db", "--database" }, title = "DATABASE", arity = 1, description = "Database name or identifier") protected String db; @@ -59,8 +52,7 @@ public class StreamingCreateCdcCmd extends AbstractStreamingCmd { protected int topicPartition = 3; /** {@inheritDoc} */ - public void execute() - throws TenantNotFoundException { + public void execute() { } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingDeleteCdcCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingDeleteCdcCmd.java index 6a1a73f..7858289 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingDeleteCdcCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingDeleteCdcCmd.java @@ -20,13 +20,8 @@ * #L% */ -import com.dtsx.astra.cli.core.AbstractConnectedCmd; import com.dtsx.astra.cli.streaming.AbstractStreamingCmd; -import com.dtsx.astra.cli.streaming.exception.TenantNotFoundException; -import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; -import com.github.rvesse.airline.annotations.Option; -import com.github.rvesse.airline.annotations.restrictions.Required; /** * Display information relative to a db. @@ -37,8 +32,7 @@ public class StreamingDeleteCdcCmd extends AbstractStreamingCmd { /** {@inheritDoc} */ - public void execute() - throws TenantNotFoundException { + public void execute() { } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingGetCdcCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingGetCdcCmd.java index 72ea255..adcdc17 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingGetCdcCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/cdc/StreamingGetCdcCmd.java @@ -20,13 +20,8 @@ * #L% */ -import com.dtsx.astra.cli.core.AbstractConnectedCmd; import com.dtsx.astra.cli.streaming.AbstractStreamingCmd; -import com.dtsx.astra.cli.streaming.exception.TenantNotFoundException; -import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; -import com.github.rvesse.airline.annotations.Option; -import com.github.rvesse.airline.annotations.restrictions.Required; /** * Display information relative to a db. @@ -37,8 +32,7 @@ public class StreamingGetCdcCmd extends AbstractStreamingCmd { /** {@inheritDoc} */ - public void execute() - throws TenantNotFoundException { + public void execute() { } diff --git a/src/main/java/com/dtsx/astra/cli/streaming/pulsarshell/PulsarShellCmd.java b/src/main/java/com/dtsx/astra/cli/streaming/pulsarshell/PulsarShellCmd.java index 235b1af..2d52b0b 100644 --- a/src/main/java/com/dtsx/astra/cli/streaming/pulsarshell/PulsarShellCmd.java +++ b/src/main/java/com/dtsx/astra/cli/streaming/pulsarshell/PulsarShellCmd.java @@ -23,7 +23,7 @@ import com.dtsx.astra.cli.core.AbstractConnectedCmd; import com.dtsx.astra.cli.core.exception.CannotStartProcessException; import com.dtsx.astra.cli.core.exception.FileSystemException; -import com.dtsx.astra.cli.streaming.OperationsStreaming; +import com.dtsx.astra.cli.streaming.ServiceStreaming; import com.dtsx.astra.cli.streaming.exception.TenantNotFoundException; import com.github.rvesse.airline.annotations.Arguments; import com.github.rvesse.airline.annotations.Command; @@ -76,7 +76,7 @@ public void execute() options.setFailOnError(failOnError); options.setFileName(fileName); options.setNoProgress(noProgress); - OperationsStreaming.startPulsarShell(options, tenant); + ServiceStreaming.startPulsarShell(options, tenant); } } diff --git a/src/main/resources/META-INF/native-image/reflect-config.json b/src/main/resources/META-INF/native-image/reflect-config.json index f0630b2..1897527 100644 --- a/src/main/resources/META-INF/native-image/reflect-config.json +++ b/src/main/resources/META-INF/native-image/reflect-config.json @@ -92,6 +92,7 @@ "methods":[{"name":"","parameterTypes":[] }]} , + { "name":"com.dtsx.astra.cli.db.dsbulk.AbstractDsbulkCmd", "allDeclaredFields":true @@ -103,8 +104,8 @@ { "name":"com.dtsx.astra.cli.db.dsbulk.DbCountCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, { "name":"com.dtsx.astra.cli.db.dsbulk.DbLoadCmd", "allDeclaredFields":true, @@ -121,79 +122,124 @@ { "name":"com.dtsx.astra.cli.db.keyspace.DbCreateKeyspaceCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, { "name":"com.dtsx.astra.cli.db.keyspace.DbListKeyspacesCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, + { - "name":"com.dtsx.astra.cli.iam.RoleGetCmd", + "name":"com.dtsx.astra.cli.db.tool.DbGraphqlPlaygroundCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, { - "name":"com.dtsx.astra.cli.iam.RoleListCmd", + "name":"com.dtsx.astra.cli.db.tool.DbSwaggerUICmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, - + "methods":[{"name":"","parameterTypes":[] }] + }, { - "name":"com.dtsx.astra.cli.iam.UserDeleteCmd", + "name":"com.dtsx.astra.cli.db.region.DbListRegionsClassicCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, { - "name":"com.dtsx.astra.cli.iam.UserGetCmd", + "name":"com.dtsx.astra.cli.db.region.DbListRegionsServerlessCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, { - "name":"com.dtsx.astra.cli.iam.UserInviteCmd", + "name":"com.dtsx.astra.cli.db.region.DbCreateRegionCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, { - "name":"com.dtsx.astra.cli.iam.UserListCmd", + "name":"com.dtsx.astra.cli.db.region.DbDeleteRegionCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"com.dtsx.astra.cli.db.region.DbListRegionsCmd", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }] + } , + { + "name":"com.dtsx.astra.cli.iam.role.RoleGetCmd", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"com.dtsx.astra.cli.iam.role.RoleListCmd", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }] + }, + + { - "name":"com.dtsx.astra.cli.org.OrgCmd", + "name":"com.dtsx.astra.cli.iam.token.TokenCreateCmd", "allDeclaredFields":true, "methods":[{"name":"","parameterTypes":[] }] }, { - "name":"com.dtsx.astra.cli.org.OrgIdCmd", + "name":"com.dtsx.astra.cli.iam.token.TokenDeleteCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, { - "name":"com.dtsx.astra.cli.db.DbListRegionsClassicCmd", + "name":"com.dtsx.astra.cli.iam.token.TokenListCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, + + { - "name":"com.dtsx.astra.cli.db.DbListRegionsServerlessCmd", + "name":"com.dtsx.astra.cli.iam.user.UserDeleteCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, { - "name":"com.dtsx.astra.cli.org.OrgNameCmd", + "name":"com.dtsx.astra.cli.iam.user.UserGetCmd", "allDeclaredFields":true, - "methods":[{"name":"","parameterTypes":[] }]} -, + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"com.dtsx.astra.cli.iam.user.UserInviteCmd", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"com.dtsx.astra.cli.iam.user.UserListCmd", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"com.dtsx.astra.cli.org.OrgCmd", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"com.dtsx.astra.cli.org.OrgIdCmd", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"com.dtsx.astra.cli.org.OrgNameCmd", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }] + }, { diff --git a/src/test/java/com/dtsx/astra/cli/test/db/DbCommandsTest.java b/src/test/java/com/dtsx/astra/cli/test/db/DbCommandsTest.java index f73e2f4..3b1c343 100644 --- a/src/test/java/com/dtsx/astra/cli/test/db/DbCommandsTest.java +++ b/src/test/java/com/dtsx/astra/cli/test/db/DbCommandsTest.java @@ -9,15 +9,15 @@ import com.dtsx.astra.cli.core.TokenOptions; import com.dtsx.astra.cli.core.exception.InvalidArgumentException; import com.dtsx.astra.cli.core.out.OutputFormat; -import com.dtsx.astra.cli.db.DatabaseService; -import com.dtsx.astra.cli.db.cqlsh.CqlShellService; -import com.dtsx.astra.cli.db.dsbulk.DsBulkService; +import com.dtsx.astra.cli.db.ServiceDatabase; +import com.dtsx.astra.cli.db.cqlsh.ServiceCqlShell; +import com.dtsx.astra.cli.db.dsbulk.ServiceDsBulk; import com.dtsx.astra.cli.utils.AstraCliUtils; import org.junit.jupiter.api.*; import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; import com.dtsx.astra.cli.core.ExitCode; -import com.dtsx.astra.cli.db.DatabaseDao; +import com.dtsx.astra.cli.db.DaoDatabase; import com.dtsx.astra.cli.db.exception.DatabaseNameNotUniqueException; import com.dtsx.astra.cli.test.AbstractCmdTest; @@ -74,7 +74,7 @@ public void testShouldCreateDb() throws DatabaseNameNotUniqueException { // When assertSuccessCli("db create %s --if-not-exist --wait".formatted(DB_TEST)); // Then - Assertions.assertTrue(DatabaseDao.getInstance().getDatabaseClient(DB_TEST).isPresent()); + Assertions.assertTrue(DaoDatabase.getInstance().getDatabaseClient(DB_TEST).isPresent()); // Database is pending assertSuccessCli("db status %s".formatted(DB_TEST)); } @@ -146,8 +146,8 @@ public void testShouldResumeDb() { public void testShouldInstallCqlsh() { if (!disableTools) { new File(AstraCliUtils.ASTRA_HOME + File.separator + "cqlsh-astra").delete(); - CqlShellService.getInstance().install(); - Assertions.assertTrue(CqlShellService.getInstance().isInstalled()); + ServiceCqlShell.getInstance().install(); + Assertions.assertTrue(ServiceCqlShell.getInstance().isInstalled()); } } @@ -168,8 +168,8 @@ public void testShouldInstallDsbulk() { + "dsbulk-" + AstraCliUtils.readProperty("dsbulk.version")).delete(); // install - DsBulkService.getInstance().install(); - Assertions.assertTrue(DsBulkService.getInstance().isInstalled()); + ServiceDsBulk.getInstance().install(); + Assertions.assertTrue(ServiceDsBulk.getInstance().isInstalled()); } } @@ -244,10 +244,17 @@ public void testShouldThrowInvalidArgument() { OutputFormat.HUMAN, AstraConfiguration.getDefaultConfigurationFileName())); CliContext.getInstance().initToken(new TokenOptions(null, AstraConfiguration.ASTRARC_DEFAULT)); - DatabaseService.getInstance().generateDotEnvFile(DB_TEST, DB_TEST, "invalid", "/tmp"); + ServiceDatabase.getInstance().generateDotEnvFile(DB_TEST, DB_TEST, "invalid", "/tmp"); }); } + @Test + @Order(20) + public void showToolsURL() { + assertSuccessCli("db swagger mtg"); + assertSuccessCli("db playground mtg"); + } + @AfterAll public static void testShouldDelete() { assertSuccessCli("db delete %s --wait".formatted(DB_TEST)); diff --git a/src/test/java/com/dtsx/astra/cli/test/db/DbRegionsTest.java b/src/test/java/com/dtsx/astra/cli/test/db/DbRegionsTest.java new file mode 100644 index 0000000..dc32060 --- /dev/null +++ b/src/test/java/com/dtsx/astra/cli/test/db/DbRegionsTest.java @@ -0,0 +1,32 @@ +package com.dtsx.astra.cli.test.db; + +import com.dtsx.astra.cli.test.AbstractCmdTest; +import org.junit.jupiter.api.Test; + +/** + * Crud on Db Region. + */ +public class DbRegionsTest extends AbstractCmdTest { + + @Test + public void listRegions() { + assertSuccessCli("db list-regions workshops"); + } + + @Test + public void deleteRegions() { + assertSuccessCli("db delete-region workshops -r australiaeast --async"); + } + + @Test + public void addRegion() { + assertSuccessCli("db create-region data-modeling -r eu-west-1 --async"); + } + + @Test + public void listDb() { + assertSuccessCli("config get default"); + } + + +} diff --git a/src/test/java/com/dtsx/astra/cli/test/iam/TokensCommandsTest.java b/src/test/java/com/dtsx/astra/cli/test/iam/TokensCommandsTest.java new file mode 100644 index 0000000..c6891d2 --- /dev/null +++ b/src/test/java/com/dtsx/astra/cli/test/iam/TokensCommandsTest.java @@ -0,0 +1,54 @@ +package com.dtsx.astra.cli.test.iam; + +import com.dtsx.astra.cli.core.ExitCode; +import com.dtsx.astra.cli.iam.role.AstraToken; +import com.dtsx.astra.cli.iam.role.ServiceRole; +import com.dtsx.astra.cli.iam.token.ServiceToken; +import com.dtsx.astra.cli.test.AbstractCmdTest; +import com.dtsx.astra.sdk.org.domain.Role; +import org.junit.jupiter.api.*; + +/** + * Testing CRUD for tokens. + * + * @author Cedrick LUNVEN (@clunven) + */ +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TokensCommandsTest extends AbstractCmdTest { + + @Test + @Order(1) + public void should_list_token() { + assertSuccessCli("token list"); + assertSuccessCli("token list -v"); + assertSuccessCli("token list --no-color"); + assertSuccessCli("token list -o json"); + assertSuccessCli("token list -o csv"); + } + + @Test + @Order(2) + public void should_list_token_errors() { + assertExitCodeCli(ExitCode.INVALID_ARGUMENT, "token list -w"); + assertExitCodeCli(ExitCode.INVALID_ARGUMENT, "token list DB"); + assertExitCodeCli(ExitCode.INVALID_ARGUMENT, "token coaster"); + assertExitCodeCli(ExitCode.INVALID_OPTION_VALUE, "token list -o yaml"); + } + + @Test + @Order(3) + public void should_create_delete_token() { + // Given + assertSuccessCli("token list"); + Role role = ServiceRole.getInstance().get("Database Administrator"); + // When + assertSuccessCli("token create -r " + role.getId()); + AstraToken token = ServiceToken.getInstance().createToken(role.getId()); + // Then + Assertions.assertTrue(ServiceToken.getInstance().tokenExist(token.clientId())); + // When + assertSuccessCli("token delete " + token.clientId()); + // Then + Assertions.assertFalse(ServiceToken.getInstance().tokenExist(token.clientId())); + } +}