Browse Source

Merge pull request #196 from thingsboard/feature/TB-65

TB-65: Unix install/upgrade scripts.
pull/198/head
Igor Kulikov 9 years ago
committed by GitHub
parent
commit
2eef2c0253
  1. 15
      application/build.gradle
  2. 39
      application/pom.xml
  3. 194
      application/src/main/data/upgrade/1.3.0/schema_update.cql
  4. 82
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  5. 5
      application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java
  6. 132
      application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java
  7. 23
      application/src/main/java/org/thingsboard/server/service/install/DatabaseUpgradeService.java
  8. 9
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  9. 26
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java
  10. 37
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  11. 2
      application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java
  12. 2
      application/src/main/java/org/thingsboard/server/service/install/cql/CQLStatementsParser.java
  13. 169
      application/src/main/java/org/thingsboard/server/service/install/cql/CassandraDbHelper.java
  14. 63
      application/src/main/scripts/install/install.sh
  15. 58
      application/src/main/scripts/install/logback.xml
  16. 62
      application/src/main/scripts/install/upgrade.sh
  17. 4
      dao/src/main/java/org/thingsboard/server/dao/cassandra/AbstractCassandraCluster.java
  18. 12
      pom.xml

15
application/build.gradle

@ -57,6 +57,21 @@ ospackage {
into "bin"
}
// Copy the install files
from("target/bin/install/install.sh") {
fileMode 0775
into "bin/install"
}
from("target/bin/install/upgrade.sh") {
fileMode 0775
into "bin/install"
}
from("target/bin/install/logback.xml") {
into "bin/install"
}
// Copy the config files
from("target/conf") {
exclude "${pkgName}.conf"

39
application/pom.xml

@ -27,7 +27,7 @@
<artifactId>application</artifactId>
<packaging>jar</packaging>
<name>Thingsboard Server Application</name>
<name>ThingsBoard Server Application</name>
<url>https://thingsboard.io</url>
<description>Open-source IoT Platform - Device management, data collection, processing and visualization
</description>
@ -137,6 +137,14 @@
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
@ -367,6 +375,29 @@
</filters>
</configuration>
</execution>
<execution>
<id>copy-install</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/bin/install</outputDirectory>
<resources>
<resource>
<directory>src/main/scripts/install</directory>
<includes>
<include>**/*.sh</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
<filters>
<filter>src/main/filters/unix.properties</filter>
</filters>
</configuration>
</execution>
<execution>
<id>copy-windows-control</id>
<phase>process-resources</phase>
@ -387,7 +418,7 @@
</configuration>
</execution>
<execution>
<id>copy-data-cql</id>
<id>copy-data</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
@ -395,10 +426,14 @@
<configuration>
<outputDirectory>${project.build.directory}/data</outputDirectory>
<resources>
<resource>
<directory>src/main/data</directory>
</resource>
<resource>
<directory>../dao/src/main/resources</directory>
<includes>
<include>**/*.cql</include>
<include>**/*.sql</include>
</includes>
<filtering>false</filtering>
</resource>

194
application/src/main/data/upgrade/1.3.0/schema_update.cql

@ -0,0 +1,194 @@
--
-- Copyright © 2016-2017 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.
--
DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_tenant_and_name;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_tenant_and_search_text;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_tenant_by_type_and_search_text;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_customer_and_search_text;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_customer_by_type_and_search_text;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_types_by_tenant;
DROP TABLE IF EXISTS thingsboard.device;
CREATE TABLE IF NOT EXISTS thingsboard.device (
id timeuuid,
tenant_id timeuuid,
customer_id timeuuid,
name text,
type text,
search_text text,
additional_info text,
PRIMARY KEY (id, tenant_id, customer_id, type)
);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_name AS
SELECT *
from thingsboard.device
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( tenant_id, name, id, customer_id, type)
WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_search_text AS
SELECT *
from thingsboard.device
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( tenant_id, search_text, id, customer_id, type)
WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_by_type_and_search_text AS
SELECT *
from thingsboard.device
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( tenant_id, type, search_text, id, customer_id)
WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_and_search_text AS
SELECT *
from thingsboard.device
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( customer_id, tenant_id, search_text, id, type )
WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC );
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_by_type_and_search_text AS
SELECT *
from thingsboard.device
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( customer_id, tenant_id, type, search_text, id )
WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC );
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_types_by_tenant AS
SELECT *
from thingsboard.device
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( (type, tenant_id), id, customer_id)
WITH CLUSTERING ORDER BY ( id ASC, customer_id DESC);
DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_tenant_and_name;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_tenant_and_search_text;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_tenant_by_type_and_search_text;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_customer_and_search_text;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_customer_by_type_and_search_text;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_types_by_tenant;
DROP TABLE IF EXISTS thingsboard.asset;
CREATE TABLE IF NOT EXISTS thingsboard.asset (
id timeuuid,
tenant_id timeuuid,
customer_id timeuuid,
name text,
type text,
search_text text,
additional_info text,
PRIMARY KEY (id, tenant_id, customer_id, type)
);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_name AS
SELECT *
from thingsboard.asset
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( tenant_id, name, id, customer_id, type)
WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_search_text AS
SELECT *
from thingsboard.asset
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( tenant_id, search_text, id, customer_id, type)
WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_by_type_and_search_text AS
SELECT *
from thingsboard.asset
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( tenant_id, type, search_text, id, customer_id)
WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_and_search_text AS
SELECT *
from thingsboard.asset
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( customer_id, tenant_id, search_text, id, type )
WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC );
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_by_type_and_search_text AS
SELECT *
from thingsboard.asset
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( customer_id, tenant_id, type, search_text, id )
WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC );
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_types_by_tenant AS
SELECT *
from thingsboard.asset
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( (type, tenant_id), id, customer_id)
WITH CLUSTERING ORDER BY ( id ASC, customer_id DESC);
CREATE TABLE IF NOT EXISTS thingsboard.alarm (
id timeuuid,
tenant_id timeuuid,
type text,
originator_id timeuuid,
originator_type text,
severity text,
status text,
start_ts bigint,
end_ts bigint,
ack_ts bigint,
clear_ts bigint,
details text,
propagate boolean,
PRIMARY KEY ((tenant_id, originator_id, originator_type), type, id)
) WITH CLUSTERING ORDER BY ( type ASC, id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.alarm_by_id AS
SELECT *
from thingsboard.alarm
WHERE tenant_id IS NOT NULL AND originator_id IS NOT NULL AND originator_type IS NOT NULL AND type IS NOT NULL
AND type IS NOT NULL AND id IS NOT NULL
PRIMARY KEY (id, tenant_id, originator_id, originator_type, type)
WITH CLUSTERING ORDER BY ( tenant_id ASC, originator_id ASC, originator_type ASC, type ASC);
DROP MATERIALIZED VIEW IF EXISTS thingsboard.relation_by_type_and_child_type;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.reverse_relation;
DROP TABLE IF EXISTS thingsboard.relation;
CREATE TABLE IF NOT EXISTS thingsboard.relation (
from_id timeuuid,
from_type text,
to_id timeuuid,
to_type text,
relation_type_group text,
relation_type text,
additional_info text,
PRIMARY KEY ((from_id, from_type), relation_type_group, relation_type, to_id, to_type)
) WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, to_id ASC, to_type ASC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.relation_by_type_and_child_type AS
SELECT *
from thingsboard.relation
WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type_group IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL
PRIMARY KEY ((from_id, from_type), relation_type_group, relation_type, to_type, to_id)
WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, to_type ASC, to_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.reverse_relation AS
SELECT *
from thingsboard.relation
WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type_group IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL
PRIMARY KEY ((to_id, to_type), relation_type_group, relation_type, from_id, from_type)
WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, from_id ASC, from_type ASC);

82
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -25,6 +25,7 @@ import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.install.DatabaseSchemaService;
import org.thingsboard.server.service.install.DatabaseUpgradeService;
import org.thingsboard.server.service.install.SystemDataLoaderService;
import java.nio.file.Files;
@ -35,6 +36,12 @@ import java.nio.file.Paths;
@Slf4j
public class ThingsboardInstallService {
@Value("${install.upgrade:false}")
private Boolean isUpgrade;
@Value("${install.upgrade.from_version:1.2.3}")
private String upgradeFromVersion;
@Value("${install.data_dir}")
private String dataDir;
@ -44,6 +51,9 @@ public class ThingsboardInstallService {
@Autowired
private DatabaseSchemaService databaseSchemaService;
@Autowired
private DatabaseUpgradeService databaseUpgradeService;
@Autowired
private ComponentDiscoveryService componentDiscoveryService;
@ -55,35 +65,67 @@ public class ThingsboardInstallService {
public void performInstall() {
try {
log.info("Starting ThingsBoard Installation...");
if (isUpgrade) {
log.info("Starting ThingsBoard Upgrade from version {} ...", upgradeFromVersion);
if (this.dataDir == null) {
throw new RuntimeException("'install.data_dir' property should specified!");
}
if (!Files.isDirectory(Paths.get(this.dataDir))) {
throw new RuntimeException("'install.data_dir' property value is not a valid directory!");
}
switch (upgradeFromVersion) {
case "1.2.3":
log.info("Upgrading ThingsBoard from version {} to 1.3.0 ...", upgradeFromVersion);
databaseUpgradeService.upgradeDatabase(upgradeFromVersion);
log.info("Updating system data...");
log.info("Installing DataBase schema...");
systemDataLoaderService.deleteSystemWidgetBundle("charts");
systemDataLoaderService.deleteSystemWidgetBundle("cards");
systemDataLoaderService.deleteSystemWidgetBundle("maps");
systemDataLoaderService.deleteSystemWidgetBundle("analogue_gauges");
systemDataLoaderService.deleteSystemWidgetBundle("digital_gauges");
systemDataLoaderService.deleteSystemWidgetBundle("gpio_widgets");
systemDataLoaderService.deleteSystemWidgetBundle("alarm_widgets");
databaseSchemaService.createDatabaseSchema();
systemDataLoaderService.loadSystemWidgets();
log.info("Loading system data...");
break;
default:
throw new RuntimeException("Unable to upgrade ThingsBoard, unsupported fromVersion: " + upgradeFromVersion);
componentDiscoveryService.discoverComponents();
}
log.info("Upgrade finished successfully!");
systemDataLoaderService.createSysAdmin();
systemDataLoaderService.createAdminSettings();
systemDataLoaderService.loadSystemWidgets();
systemDataLoaderService.loadSystemPlugins();
systemDataLoaderService.loadSystemRules();
} else {
if (loadDemo) {
log.info("Loading demo data...");
systemDataLoaderService.loadDemoData();
log.info("Starting ThingsBoard Installation...");
if (this.dataDir == null) {
throw new RuntimeException("'install.data_dir' property should specified!");
}
if (!Files.isDirectory(Paths.get(this.dataDir))) {
throw new RuntimeException("'install.data_dir' property value is not a valid directory!");
}
log.info("Installing DataBase schema...");
databaseSchemaService.createDatabaseSchema();
log.info("Loading system data...");
componentDiscoveryService.discoverComponents();
systemDataLoaderService.createSysAdmin();
systemDataLoaderService.createAdminSettings();
systemDataLoaderService.loadSystemWidgets();
systemDataLoaderService.loadSystemPlugins();
systemDataLoaderService.loadSystemRules();
if (loadDemo) {
log.info("Loading demo data...");
systemDataLoaderService.loadDemoData();
}
log.info("Installation finished successfully!");
}
log.info("Finished!");
} catch (Exception e) {
log.error("Unexpected error during ThingsBoard installation!", e);
throw new ThingsboardInstallException("Unexpected error during ThingsBoard installation!", e);

5
application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseSchemaService.java

@ -23,7 +23,7 @@ import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.server.dao.cassandra.CassandraInstallCluster;
import org.thingsboard.server.dao.util.NoSqlDao;
import org.thingsboard.server.install.cql.CQLStatementsParser;
import org.thingsboard.server.service.install.cql.CQLStatementsParser;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -35,6 +35,7 @@ import java.util.List;
@Slf4j
public class CassandraDatabaseSchemaService implements DatabaseSchemaService {
private static final String CASSANDRA_DIR = "cassandra";
private static final String SCHEMA_CQL = "schema.cql";
@Value("${install.data_dir}")
@ -47,7 +48,7 @@ public class CassandraDatabaseSchemaService implements DatabaseSchemaService {
public void createDatabaseSchema() throws Exception {
log.info("Installing Cassandra DataBase schema...");
Path schemaFile = Paths.get(this.dataDir, SCHEMA_CQL);
Path schemaFile = Paths.get(this.dataDir, CASSANDRA_DIR, SCHEMA_CQL);
loadCql(schemaFile);
}

132
application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java

@ -0,0 +1,132 @@
/**
* Copyright © 2016-2017 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 com.datastax.driver.core.KeyspaceMetadata;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.cassandra.CassandraInstallCluster;
import org.thingsboard.server.dao.util.NoSqlDao;
import org.thingsboard.server.service.install.cql.CQLStatementsParser;
import org.thingsboard.server.service.install.cql.CassandraDbHelper;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
@Service
@NoSqlDao
@Profile("install")
@Slf4j
public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
private static final String SCHEMA_UPDATE_CQL = "schema_update.cql";
@Value("${install.data_dir}")
private String dataDir;
@Autowired
private CassandraCluster cluster;
@Autowired
private CassandraInstallCluster installCluster;
@Override
public void upgradeDatabase(String fromVersion) throws Exception {
switch (fromVersion) {
case "1.2.3":
log.info("Upgrading Cassandara DataBase from version {} to 1.3.0 ...", fromVersion);
//Dump devices, assets and relations
KeyspaceMetadata ks = cluster.getCluster().getMetadata().getKeyspace(cluster.getKeyspaceName());
log.info("Dumping devices ...");
Path devicesDump = CassandraDbHelper.dumpCfIfExists(ks, cluster.getSession(), "device",
new String[]{"id", "tenant_id", "customer_id", "name", "search_text", "additional_info"},
"tb-devices");
if (devicesDump != null) {
CassandraDbHelper.appendToEndOfLine(devicesDump, "default");
}
log.info("Devices dumped.");
log.info("Dumping assets ...");
Path assetsDump = CassandraDbHelper.dumpCfIfExists(ks, cluster.getSession(), "asset",
new String[]{"id", "tenant_id", "customer_id", "name", "search_text", "additional_info", "type"},
"tb-assets");
log.info("Assets dumped.");
log.info("Dumping relations ...");
Path relationsDump = CassandraDbHelper.dumpCfIfExists(ks, cluster.getSession(), "relation",
new String[]{"from_id", "from_type", "to_id", "to_type", "relation_type", "additional_info"},
"tb-relations");
if (relationsDump != null) {
CassandraDbHelper.appendToEndOfLine(relationsDump, "COMMON");
}
log.info("Relations dumped.");
log.info("Updating schema ...");
Path schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.3.0", SCHEMA_UPDATE_CQL);
loadCql(schemaUpdateFile);
log.info("Schema updated.");
//Restore devices, assets and relations
log.info("Restoring devices ...");
if (devicesDump != null) {
CassandraDbHelper.loadCf(ks, cluster.getSession(), "device",
new String[]{"id", "tenant_id", "customer_id", "name", "search_text", "additional_info", "type"}, devicesDump);
Files.deleteIfExists(devicesDump);
}
log.info("Devices restored.");
log.info("Restoring assets ...");
if (assetsDump != null) {
CassandraDbHelper.loadCf(ks, cluster.getSession(), "asset",
new String[]{"id", "tenant_id", "customer_id", "name", "search_text", "additional_info", "type"}, assetsDump);
Files.deleteIfExists(assetsDump);
}
log.info("Assets restored.");
log.info("Restoring relations ...");
if (relationsDump != null) {
CassandraDbHelper.loadCf(ks, cluster.getSession(), "relation",
new String[]{"from_id", "from_type", "to_id", "to_type", "relation_type", "additional_info", "relation_type_group"}, relationsDump);
Files.deleteIfExists(relationsDump);
}
log.info("Relations restored.");
break;
default:
throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion);
}
}
private void loadCql(Path cql) throws Exception {
List<String> statements = new CQLStatementsParser(cql).getStatements();
statements.forEach(statement -> installCluster.getSession().execute(statement));
}
}

23
application/src/main/java/org/thingsboard/server/service/install/DatabaseUpgradeService.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2017 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 DatabaseUpgradeService {
void upgradeDatabase(String fromVersion) throws Exception;
}

9
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -41,6 +41,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.plugin.PluginService;
import org.thingsboard.server.dao.rule.RuleService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
@ -227,6 +228,14 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
loadDashboards(Paths.get(dataDir, JSON_DIR, DEMO_DIR, DASHBOARDS_DIR), demoTenant.getId(), null);
}
@Override
public void deleteSystemWidgetBundle(String bundleAlias) throws Exception {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(new TenantId(ModelConstants.NULL_UUID), bundleAlias);
if (widgetsBundle != null) {
widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getId());
}
}
private User createUser(Authority authority,
TenantId tenantId,
CustomerId customerId,

26
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseSchemaService.java

@ -22,20 +22,44 @@ import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.server.dao.util.SqlDao;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
@Service
@Profile("install")
@Slf4j
@SqlDao
public class SqlDatabaseSchemaService implements DatabaseSchemaService {
private static final String SQL_DIR = "sql";
private static final String SCHEMA_SQL = "schema.sql";
@Value("${install.data_dir}")
private String dataDir;
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String dbUserName;
@Value("${spring.datasource.password}")
private String dbPassword;
@Override
public void createDatabaseSchema() throws Exception {
log.info("Installing SQL DataBase schema...");
//TODO:
Path schemaFile = Paths.get(this.dataDir, SQL_DIR, SCHEMA_SQL);
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
String sql = new String(Files.readAllBytes(schemaFile), Charset.forName("UTF-8"));
conn.createStatement().execute(sql);
}
}

37
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -0,0 +1,37 @@
/**
* Copyright © 2016-2017 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 lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.server.dao.util.SqlDao;
@Service
@Profile("install")
@Slf4j
@SqlDao
public class SqlDatabaseUpgradeService implements DatabaseUpgradeService {
@Override
public void upgradeDatabase(String fromVersion) throws Exception {
switch (fromVersion) {
default:
throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
}
}
}

2
application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java

@ -29,4 +29,6 @@ public interface SystemDataLoaderService {
void loadDemoData() throws Exception;
void deleteSystemWidgetBundle(String bundleAlias) throws Exception;
}

2
application/src/main/java/org/thingsboard/server/install/cql/CQLStatementsParser.java → application/src/main/java/org/thingsboard/server/service/install/cql/CQLStatementsParser.java

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.thingsboard.server.install.cql;
package org.thingsboard.server.service.install.cql;
import lombok.extern.slf4j.Slf4j;

169
application/src/main/java/org/thingsboard/server/service/install/cql/CassandraDbHelper.java

@ -0,0 +1,169 @@
/**
* Copyright © 2016-2017 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.cql;
import com.datastax.driver.core.*;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
public class CassandraDbHelper {
private static final CSVFormat CSV_DUMP_FORMAT = CSVFormat.DEFAULT.withNullString("\\N");
public static Path dumpCfIfExists(KeyspaceMetadata ks, Session session, String cfName,
String[] columns, String dumpPrefix) throws Exception {
if (ks.getTable(cfName) != null) {
Path dumpFile = Files.createTempFile(dumpPrefix, null);
Files.deleteIfExists(dumpFile);
try (CSVPrinter csvPrinter = new CSVPrinter(Files.newBufferedWriter(dumpFile), CSV_DUMP_FORMAT)) {
Statement stmt = new SimpleStatement("SELECT * FROM " + cfName);
stmt.setFetchSize(1000);
ResultSet rs = session.execute(stmt);
Iterator<Row> iter = rs.iterator();
while (iter.hasNext()) {
Row row = iter.next();
if (row != null) {
dumpRow(row, columns, csvPrinter);
}
}
}
return dumpFile;
} else {
return null;
}
}
public static void appendToEndOfLine(Path targetDumpFile, String toAppend) throws Exception {
Path tmp = Files.createTempFile(null, null);
try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(targetDumpFile), CSV_DUMP_FORMAT)) {
try (CSVPrinter csvPrinter = new CSVPrinter(Files.newBufferedWriter(tmp), CSV_DUMP_FORMAT)) {
csvParser.forEach(record -> {
List<String> newRecord = new ArrayList<>();
record.forEach(val -> newRecord.add(val));
newRecord.add(toAppend);
try {
csvPrinter.printRecord(newRecord);
} catch (IOException e) {
throw new RuntimeException("Error appending to EOL", e);
}
});
}
}
Files.move(tmp, targetDumpFile, StandardCopyOption.REPLACE_EXISTING);
}
public static void loadCf(KeyspaceMetadata ks, Session session, String cfName, String[] columns, Path sourceFile) throws Exception {
TableMetadata tableMetadata = ks.getTable(cfName);
PreparedStatement prepared = session.prepare(createInsertStatement(cfName, columns));
try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(sourceFile), CSV_DUMP_FORMAT.withHeader(columns))) {
csvParser.forEach(record -> {
BoundStatement boundStatement = prepared.bind();
for (String column : columns) {
setColumnValue(tableMetadata, column, record, boundStatement);
}
session.execute(boundStatement);
});
}
}
private static void dumpRow(Row row, String[] columns, CSVPrinter csvPrinter) throws Exception {
List<String> record = new ArrayList<>();
for (String column : columns) {
record.add(getColumnValue(column, row));
}
csvPrinter.printRecord(record);
}
private static String getColumnValue(String column, Row row) {
String str = "";
int index = row.getColumnDefinitions().getIndexOf(column);
if (index > -1) {
DataType type = row.getColumnDefinitions().getType(index);
try {
if (row.isNull(index)) {
return null;
} else if (type == DataType.cdouble()) {
str = new Double(row.getDouble(index)).toString();
} else if (type == DataType.cint()) {
str = new Integer(row.getInt(index)).toString();
} else if (type == DataType.uuid()) {
str = row.getUUID(index).toString();
} else if (type == DataType.timeuuid()) {
str = row.getUUID(index).toString();
} else if (type == DataType.cfloat()) {
str = new Float(row.getFloat(index)).toString();
} else if (type == DataType.timestamp()) {
str = ""+row.getTimestamp(index).getTime();
} else {
str = row.getString(index);
}
} catch (Exception e) {
str = "";
}
}
return str;
}
private static String createInsertStatement(String cfName, String[] columns) {
StringBuilder insertStatementBuilder = new StringBuilder();
insertStatementBuilder.append("INSERT INTO ").append(cfName).append(" (");
for (String column : columns) {
insertStatementBuilder.append(column).append(",");
}
insertStatementBuilder.deleteCharAt(insertStatementBuilder.length() - 1);
insertStatementBuilder.append(") VALUES (");
for (String column : columns) {
insertStatementBuilder.append("?").append(",");
}
insertStatementBuilder.deleteCharAt(insertStatementBuilder.length() - 1);
insertStatementBuilder.append(")");
return insertStatementBuilder.toString();
}
private static void setColumnValue(TableMetadata tableMetadata, String column,
CSVRecord record, BoundStatement boundStatement) {
String value = record.get(column);
DataType type = tableMetadata.getColumn(column).getType();
if (value == null) {
boundStatement.setToNull(column);
} else if (type == DataType.cdouble()) {
boundStatement.setDouble(column, Double.valueOf(value));
} else if (type == DataType.cint()) {
boundStatement.setInt(column, Integer.valueOf(value));
} else if (type == DataType.uuid()) {
boundStatement.setUUID(column, UUID.fromString(value));
} else if (type == DataType.timeuuid()) {
boundStatement.setUUID(column, UUID.fromString(value));
} else if (type == DataType.cfloat()) {
boundStatement.setFloat(column, Float.valueOf(value));
} else if (type == DataType.timestamp()) {
boundStatement.setTimestamp(column, new Date(Long.valueOf(value)));
} else {
boundStatement.setString(column, value);
}
}
}

63
application/src/main/scripts/install/install.sh

@ -0,0 +1,63 @@
#!/bin/bash
#
# Copyright © 2016-2017 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.
#
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
--loadDemo)
LOAD_DEMO=true
shift # past argument
;;
*)
# unknown option
;;
esac
shift # past argument or value
done
if [ "$LOAD_DEMO" == "true" ]; then
loadDemo=true
else
loadDemo=false
fi
CONF_FOLDER=${pkg.installFolder}/conf
configfile=${pkg.name}.conf
jarfile=${pkg.installFolder}/bin/${pkg.name}.jar
installDir=${pkg.installFolder}/data
source "${CONF_FOLDER}/${configfile}"
run_user=${pkg.name}
su -s /bin/sh -c "java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \
-Dinstall.data_dir=${installDir} \
-Dinstall.load_demo=${loadDemo} \
-Dspring.jpa.hibernate.ddl-auto=none \
-Dinstall.upgrade=false \
-Dlogging.config=${pkg.installFolder}/bin/install/logback.xml \
org.springframework.boot.loader.PropertiesLauncher" "$run_user"
if [ $? -ne 0 ]; then
echo "ThingsBoard installation failed!"
else
echo "ThingsBoard installed successfully!"
fi
exit $?

58
application/src/main/scripts/install/logback.xml

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright © 2016-2017 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.
-->
<!DOCTYPE configuration>
<configuration>
<appender name="fileLogAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${pkg.logFolder}/install.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${pkg.logFolder}/install.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<logger name="org.thingsboard.server.install" level="INFO">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.thingsboard.server.service.install" level="INFO">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.thingsboard.server" level="INFO" />
<logger name="akka" level="INFO" />
<root level="INFO">
<appender-ref ref="fileLogAppender"/>
</root>
</configuration>

62
application/src/main/scripts/install/upgrade.sh

@ -0,0 +1,62 @@
#!/bin/bash
#
# Copyright © 2016-2017 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.
#
for i in "$@"
do
case $i in
--fromVersion=*)
FROM_VERSION="${i#*=}"
shift
;;
*)
# unknown option
;;
esac
done
if [[ -z "${FROM_VERSION// }" ]]; then
echo "--fromVersion parameter is invalid or unspecified!"
echo "Usage: upgrade.sh --fromVersion={VERSION}"
exit 1
else
fromVersion="${FROM_VERSION// }"
fi
CONF_FOLDER=${pkg.installFolder}/conf
configfile=${pkg.name}.conf
jarfile=${pkg.installFolder}/bin/${pkg.name}.jar
installDir=${pkg.installFolder}/data
source "${CONF_FOLDER}/${configfile}"
run_user=${pkg.name}
su -s /bin/sh -c "java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \
-Dinstall.data_dir=${installDir} \
-Dspring.jpa.hibernate.ddl-auto=none \
-Dinstall.upgrade=true \
-Dinstall.upgrade.from_version=${fromVersion} \
-Dlogging.config=${pkg.installFolder}/bin/install/logback.xml \
org.springframework.boot.loader.PropertiesLauncher" "$run_user"
if [ $? -ne 0 ]; then
echo "ThingsBoard upgrade failed!"
else
echo "ThingsBoard upgraded successfully!"
fi
exit $?

4
dao/src/main/java/org/thingsboard/server/dao/cassandra/AbstractCassandraCluster.java

@ -127,6 +127,10 @@ public abstract class AbstractCassandraCluster {
}
}
public String getKeyspaceName() {
return keyspaceName;
}
private boolean isInstall() {
return environment.acceptsProfiles("install");
}

12
pom.xml

@ -46,6 +46,8 @@
<guava.version>18.0</guava.version>
<commons-lang3.version>3.4</commons-lang3.version>
<commons-validator.version>1.5.0</commons-validator.version>
<commons-io.version>2.5</commons-io.version>
<commons-csv.version>1.4</commons-csv.version>
<jackson.version>2.8.8.1</jackson.version>
<json-schema-validator.version>2.2.6</json-schema-validator.version>
<scala.version>2.11</scala.version>
@ -565,6 +567,16 @@
<artifactId>commons-validator</artifactId>
<version>${commons-validator.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>${commons-csv.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>

Loading…
Cancel
Save