Cassandra cloud connect to Datastax Astra DB using SECURE_BUNDLE, CLIENT_ID and CLIENT_SECRET
This commit is contained in:
		
							parent
							
								
									5891a1df65
								
							
						
					
					
						commit
						3c496f4749
					
				@ -26,6 +26,7 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService;
 | 
			
		||||
import org.thingsboard.server.service.install.DatabaseEntitiesUpgradeService;
 | 
			
		||||
import org.thingsboard.server.service.install.DatabaseTsUpgradeService;
 | 
			
		||||
import org.thingsboard.server.service.install.EntityDatabaseSchemaService;
 | 
			
		||||
import org.thingsboard.server.service.install.NoSqlKeyspaceService;
 | 
			
		||||
import org.thingsboard.server.service.install.SystemDataLoaderService;
 | 
			
		||||
import org.thingsboard.server.service.install.TsDatabaseSchemaService;
 | 
			
		||||
import org.thingsboard.server.service.install.TsLatestDatabaseSchemaService;
 | 
			
		||||
@ -51,6 +52,9 @@ public class ThingsboardInstallService {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private EntityDatabaseSchemaService entityDatabaseSchemaService;
 | 
			
		||||
 | 
			
		||||
    @Autowired(required = false)
 | 
			
		||||
    private NoSqlKeyspaceService noSqlKeyspaceService;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private TsDatabaseSchemaService tsDatabaseSchemaService;
 | 
			
		||||
 | 
			
		||||
@ -248,6 +252,10 @@ public class ThingsboardInstallService {
 | 
			
		||||
 | 
			
		||||
                log.info("Installing DataBase schema for timeseries...");
 | 
			
		||||
 | 
			
		||||
                if (noSqlKeyspaceService != null) {
 | 
			
		||||
                    noSqlKeyspaceService.createDatabaseSchema();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                tsDatabaseSchemaService.createDatabaseSchema();
 | 
			
		||||
 | 
			
		||||
                if (tsLatestDatabaseSchemaService != null) {
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,37 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.service.install;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.annotation.Profile;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.thingsboard.server.dao.util.NoSqlAnyDaoNonCloud;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* Create keyspace for Cassandra NoSQL database for non-cloud deployment.
 | 
			
		||||
* For cloud service like Astra DBaas admin have to create keyspace manually on cloud UI.
 | 
			
		||||
* Then create tokens with database admin role and put it on Thingsboard parameters.
 | 
			
		||||
* Without this service cloud DB will end up with exception like
 | 
			
		||||
* UnauthorizedException: Missing correct permission on thingsboard
 | 
			
		||||
* */
 | 
			
		||||
@Service
 | 
			
		||||
@NoSqlAnyDaoNonCloud
 | 
			
		||||
@Profile("install")
 | 
			
		||||
public class CassandraKeyspaceService extends CassandraAbstractDatabaseSchemaService
 | 
			
		||||
        implements NoSqlKeyspaceService {
 | 
			
		||||
    public CassandraKeyspaceService() {
 | 
			
		||||
        super("schema-keyspace.cql");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.service.install;
 | 
			
		||||
 | 
			
		||||
public interface NoSqlKeyspaceService extends DatabaseSchemaService {
 | 
			
		||||
}
 | 
			
		||||
@ -200,6 +200,14 @@ cassandra:
 | 
			
		||||
  username: "${CASSANDRA_USERNAME:}"
 | 
			
		||||
  # Specify your password
 | 
			
		||||
  password: "${CASSANDRA_PASSWORD:}"
 | 
			
		||||
  # Astra DB connect https://astra.datastax.com/
 | 
			
		||||
  cloud:
 | 
			
		||||
    # /etc/thingsboard/astra/secure-connect-thingsboard.zip
 | 
			
		||||
    secure_connect_bundle_path: "${CASSANDRA_CLOUD_SECURE_BUNDLE_PATH:}"
 | 
			
		||||
    # DucitQPHMzPCBOZqFYexAfKk
 | 
			
		||||
    client_id: "${CASSANDRA_CLOUD_CLIENT_ID:}"
 | 
			
		||||
    # ZnF7FpuHp43FP5BzM+KY8wGmSb4Ql6BhT4Z7sOU13ze+gXQ-n7OkFpNuB,oACUIQObQnK0g4bSPoZhK5ejkcF9F.j6f64j71Sr.tiRe0Fsq2hPS1ZCGSfAaIgg63IydG
 | 
			
		||||
    client_secret: "${CASSANDRA_CLOUD_CLIENT_SECRET:}"
 | 
			
		||||
 | 
			
		||||
  # Cassandra cluster connection socket parameters #
 | 
			
		||||
  socket:
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,7 @@ public class TransportNoSqlTestSuite {
 | 
			
		||||
    public static CustomCassandraCQLUnit cassandraUnit =
 | 
			
		||||
            new CustomCassandraCQLUnit(
 | 
			
		||||
                    Arrays.asList(
 | 
			
		||||
                            new ClassPathCQLDataSet("cassandra/schema-keyspace.cql", false, false),
 | 
			
		||||
                            new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false),
 | 
			
		||||
                            new ClassPathCQLDataSet("cassandra/schema-ts-latest.cql", false, false)
 | 
			
		||||
                    ),
 | 
			
		||||
 | 
			
		||||
@ -24,11 +24,13 @@ import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.core.env.Profiles;
 | 
			
		||||
import org.thingsboard.server.common.data.StringUtils;
 | 
			
		||||
import org.thingsboard.server.dao.cassandra.guava.GuavaSession;
 | 
			
		||||
import org.thingsboard.server.dao.cassandra.guava.GuavaSessionBuilder;
 | 
			
		||||
import org.thingsboard.server.dao.cassandra.guava.GuavaSessionUtils;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.PreDestroy;
 | 
			
		||||
import java.nio.file.Paths;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
public abstract class AbstractCassandraCluster {
 | 
			
		||||
@ -40,6 +42,13 @@ public abstract class AbstractCassandraCluster {
 | 
			
		||||
    @Value("${cassandra.local_datacenter:datacenter1}")
 | 
			
		||||
    private String localDatacenter;
 | 
			
		||||
 | 
			
		||||
    @Value("${cassandra.cloud.secure_connect_bundle_path:}")
 | 
			
		||||
    private String cloudSecureConnectBundlePath;
 | 
			
		||||
    @Value("${cassandra.cloud.client_id:}")
 | 
			
		||||
    private String cloudClientId;
 | 
			
		||||
    @Value("${cassandra.cloud.client_secret:}")
 | 
			
		||||
    private String cloudClientSecret;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private CassandraDriverOptions driverOptions;
 | 
			
		||||
 | 
			
		||||
@ -86,7 +95,14 @@ public abstract class AbstractCassandraCluster {
 | 
			
		||||
            this.sessionBuilder.withKeyspace(this.keyspaceName);
 | 
			
		||||
        }
 | 
			
		||||
        this.sessionBuilder.withLocalDatacenter(localDatacenter);
 | 
			
		||||
 | 
			
		||||
        if (StringUtils.isNotBlank(cloudSecureConnectBundlePath)) {
 | 
			
		||||
            this.sessionBuilder.withCloudSecureConnectBundle(Paths.get(cloudSecureConnectBundlePath));
 | 
			
		||||
            this.sessionBuilder.withAuthCredentials(cloudClientId, cloudClientSecret);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        session = sessionBuilder.build();
 | 
			
		||||
 | 
			
		||||
        if (this.metrics && this.jmx) {
 | 
			
		||||
            MetricRegistry registry =
 | 
			
		||||
                    session.getMetrics().orElseThrow(
 | 
			
		||||
 | 
			
		||||
@ -40,26 +40,8 @@ import java.util.function.Predicate;
 | 
			
		||||
 */
 | 
			
		||||
public class GuavaDriverContext extends DefaultDriverContext {
 | 
			
		||||
 | 
			
		||||
    public GuavaDriverContext(
 | 
			
		||||
            DriverConfigLoader configLoader,
 | 
			
		||||
            List<TypeCodec<?>> typeCodecs,
 | 
			
		||||
            NodeStateListener nodeStateListener,
 | 
			
		||||
            SchemaChangeListener schemaChangeListener,
 | 
			
		||||
            RequestTracker requestTracker,
 | 
			
		||||
            Map<String, String> localDatacenters,
 | 
			
		||||
            Map<String, Predicate<Node>> nodeFilters,
 | 
			
		||||
            ClassLoader classLoader) {
 | 
			
		||||
        super(
 | 
			
		||||
                configLoader,
 | 
			
		||||
                ProgrammaticArguments.builder()
 | 
			
		||||
                        .addTypeCodecs(typeCodecs.toArray(new TypeCodec<?>[0]))
 | 
			
		||||
                        .withNodeStateListener(nodeStateListener)
 | 
			
		||||
                        .withSchemaChangeListener(schemaChangeListener)
 | 
			
		||||
                        .withRequestTracker(requestTracker)
 | 
			
		||||
                        .withLocalDatacenters(localDatacenters)
 | 
			
		||||
                        .withNodeFilters(nodeFilters)
 | 
			
		||||
                        .withClassLoader(classLoader)
 | 
			
		||||
                        .build());
 | 
			
		||||
    public GuavaDriverContext(DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) {
 | 
			
		||||
        super(configLoader, programmaticArguments);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -25,18 +25,8 @@ import edu.umd.cs.findbugs.annotations.NonNull;
 | 
			
		||||
public class GuavaSessionBuilder extends SessionBuilder<GuavaSessionBuilder, GuavaSession> {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected DriverContext buildContext(
 | 
			
		||||
            DriverConfigLoader configLoader,
 | 
			
		||||
            ProgrammaticArguments programmaticArguments) {
 | 
			
		||||
        return new GuavaDriverContext(
 | 
			
		||||
                configLoader,
 | 
			
		||||
                programmaticArguments.getTypeCodecs(),
 | 
			
		||||
                programmaticArguments.getNodeStateListener(),
 | 
			
		||||
                programmaticArguments.getSchemaChangeListener(),
 | 
			
		||||
                programmaticArguments.getRequestTracker(),
 | 
			
		||||
                programmaticArguments.getLocalDatacenters(),
 | 
			
		||||
                programmaticArguments.getNodeFilters(),
 | 
			
		||||
                programmaticArguments.getClassLoader());
 | 
			
		||||
    protected DriverContext buildContext(DriverConfigLoader configLoader, ProgrammaticArguments programmaticArguments) {
 | 
			
		||||
        return new GuavaDriverContext(configLoader, programmaticArguments);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.dao.util;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
 | 
			
		||||
 | 
			
		||||
import java.lang.annotation.Retention;
 | 
			
		||||
import java.lang.annotation.RetentionPolicy;
 | 
			
		||||
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
@ConditionalOnExpression("('${database.ts.type}'=='cassandra' || '${database.ts_latest.type}'=='cassandra') " +
 | 
			
		||||
        "&& ('${cassandra.cloud.secure_connect_bundle_path}' == null || '${cassandra.cloud.secure_connect_bundle_path}'.isBlank() )")
 | 
			
		||||
public @interface NoSqlAnyDaoNonCloud {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								dao/src/main/resources/cassandra/schema-keyspace.cql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								dao/src/main/resources/cassandra/schema-keyspace.cql
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
--
 | 
			
		||||
-- Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
--
 | 
			
		||||
-- 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.
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
CREATE KEYSPACE IF NOT EXISTS thingsboard
 | 
			
		||||
WITH replication = {
 | 
			
		||||
	'class' : 'SimpleStrategy',
 | 
			
		||||
	'replication_factor' : 1
 | 
			
		||||
};
 | 
			
		||||
@ -14,12 +14,6 @@
 | 
			
		||||
-- limitations under the License.
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
CREATE KEYSPACE IF NOT EXISTS thingsboard
 | 
			
		||||
WITH replication = {
 | 
			
		||||
	'class' : 'SimpleStrategy',
 | 
			
		||||
	'replication_factor' : 1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_latest_cf (
 | 
			
		||||
    entity_type text, // (DEVICE, CUSTOMER, TENANT)
 | 
			
		||||
    entity_id timeuuid,
 | 
			
		||||
 | 
			
		||||
@ -14,12 +14,6 @@
 | 
			
		||||
-- limitations under the License.
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
CREATE KEYSPACE IF NOT EXISTS thingsboard
 | 
			
		||||
WITH replication = {
 | 
			
		||||
	'class' : 'SimpleStrategy',
 | 
			
		||||
	'replication_factor' : 1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_cf (
 | 
			
		||||
    entity_type text, // (DEVICE, CUSTOMER, TENANT)
 | 
			
		||||
    entity_id timeuuid,
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,7 @@ public class NoSqlDaoServiceTestSuite {
 | 
			
		||||
    public static CustomCassandraCQLUnit cassandraUnit =
 | 
			
		||||
            new CustomCassandraCQLUnit(
 | 
			
		||||
                    Arrays.asList(
 | 
			
		||||
                            new ClassPathCQLDataSet("cassandra/schema-keyspace.cql", false, false),
 | 
			
		||||
                            new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false),
 | 
			
		||||
                            new ClassPathCQLDataSet("cassandra/schema-ts-latest.cql", false, false)
 | 
			
		||||
                    ),
 | 
			
		||||
 | 
			
		||||
@ -63,7 +63,7 @@ Tool execution time depends on DB size, CPU resources and Disk throughput
 | 
			
		||||
* Note that this this part works only for single node Cassandra Cluster. If you have more nodes - it is better to use `sstableloader` tool.
 | 
			
		||||
 | 
			
		||||
1. [Optional] install Cassandra on the instance
 | 
			
		||||
2. [Optional] Using `cqlsh` create `thingsboard` keyspace and requred tables from this files `schema-ts.cql` and `schema-ts-latest.cql` using `source` command
 | 
			
		||||
2. [Optional] Using `cqlsh` create `thingsboard` keyspace and requred tables from this files `schema-keyspace.cql`, `schema-ts.cql` and `schema-ts-latest.cql` using `source` command
 | 
			
		||||
3. Stop Cassandra
 | 
			
		||||
4. Look at `/var/lib/cassandra/data/thingsboard` and check for names of data folders
 | 
			
		||||
5. Copy generated SSTable files into cassandra data dir using next command:
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user