Commit 2eef2c0253b554d9b3c3a7f5747e411aa48609e7

Authored by Igor Kulikov
Committed by GitHub
2 parents f274c72f f206b9f4

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

TB-65: Unix install/upgrade scripts.
... ... @@ -57,6 +57,21 @@ ospackage {
57 57 into "bin"
58 58 }
59 59
  60 + // Copy the install files
  61 + from("target/bin/install/install.sh") {
  62 + fileMode 0775
  63 + into "bin/install"
  64 + }
  65 +
  66 + from("target/bin/install/upgrade.sh") {
  67 + fileMode 0775
  68 + into "bin/install"
  69 + }
  70 +
  71 + from("target/bin/install/logback.xml") {
  72 + into "bin/install"
  73 + }
  74 +
60 75 // Copy the config files
61 76 from("target/conf") {
62 77 exclude "${pkgName}.conf"
... ...
... ... @@ -27,7 +27,7 @@
27 27 <artifactId>application</artifactId>
28 28 <packaging>jar</packaging>
29 29
30   - <name>Thingsboard Server Application</name>
  30 + <name>ThingsBoard Server Application</name>
31 31 <url>https://thingsboard.io</url>
32 32 <description>Open-source IoT Platform - Device management, data collection, processing and visualization
33 33 </description>
... ... @@ -138,6 +138,14 @@
138 138 <artifactId>velocity-tools</artifactId>
139 139 </dependency>
140 140 <dependency>
  141 + <groupId>commons-io</groupId>
  142 + <artifactId>commons-io</artifactId>
  143 + </dependency>
  144 + <dependency>
  145 + <groupId>org.apache.commons</groupId>
  146 + <artifactId>commons-csv</artifactId>
  147 + </dependency>
  148 + <dependency>
141 149 <groupId>org.springframework</groupId>
142 150 <artifactId>spring-context-support</artifactId>
143 151 </dependency>
... ... @@ -368,6 +376,29 @@
368 376 </configuration>
369 377 </execution>
370 378 <execution>
  379 + <id>copy-install</id>
  380 + <phase>process-resources</phase>
  381 + <goals>
  382 + <goal>copy-resources</goal>
  383 + </goals>
  384 + <configuration>
  385 + <outputDirectory>${project.build.directory}/bin/install</outputDirectory>
  386 + <resources>
  387 + <resource>
  388 + <directory>src/main/scripts/install</directory>
  389 + <includes>
  390 + <include>**/*.sh</include>
  391 + <include>**/*.xml</include>
  392 + </includes>
  393 + <filtering>true</filtering>
  394 + </resource>
  395 + </resources>
  396 + <filters>
  397 + <filter>src/main/filters/unix.properties</filter>
  398 + </filters>
  399 + </configuration>
  400 + </execution>
  401 + <execution>
371 402 <id>copy-windows-control</id>
372 403 <phase>process-resources</phase>
373 404 <goals>
... ... @@ -387,7 +418,7 @@
387 418 </configuration>
388 419 </execution>
389 420 <execution>
390   - <id>copy-data-cql</id>
  421 + <id>copy-data</id>
391 422 <phase>process-resources</phase>
392 423 <goals>
393 424 <goal>copy-resources</goal>
... ... @@ -396,9 +427,13 @@
396 427 <outputDirectory>${project.build.directory}/data</outputDirectory>
397 428 <resources>
398 429 <resource>
  430 + <directory>src/main/data</directory>
  431 + </resource>
  432 + <resource>
399 433 <directory>../dao/src/main/resources</directory>
400 434 <includes>
401 435 <include>**/*.cql</include>
  436 + <include>**/*.sql</include>
402 437 </includes>
403 438 <filtering>false</filtering>
404 439 </resource>
... ...
  1 +--
  2 +-- Copyright © 2016-2017 The Thingsboard Authors
  3 +--
  4 +-- Licensed under the Apache License, Version 2.0 (the "License");
  5 +-- you may not use this file except in compliance with the License.
  6 +-- You may obtain a copy of the License at
  7 +--
  8 +-- http://www.apache.org/licenses/LICENSE-2.0
  9 +--
  10 +-- Unless required by applicable law or agreed to in writing, software
  11 +-- distributed under the License is distributed on an "AS IS" BASIS,
  12 +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +-- See the License for the specific language governing permissions and
  14 +-- limitations under the License.
  15 +--
  16 +
  17 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_tenant_and_name;
  18 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_tenant_and_search_text;
  19 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_tenant_by_type_and_search_text;
  20 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_customer_and_search_text;
  21 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_by_customer_by_type_and_search_text;
  22 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.device_types_by_tenant;
  23 +
  24 +DROP TABLE IF EXISTS thingsboard.device;
  25 +
  26 +CREATE TABLE IF NOT EXISTS thingsboard.device (
  27 + id timeuuid,
  28 + tenant_id timeuuid,
  29 + customer_id timeuuid,
  30 + name text,
  31 + type text,
  32 + search_text text,
  33 + additional_info text,
  34 + PRIMARY KEY (id, tenant_id, customer_id, type)
  35 +);
  36 +
  37 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_name AS
  38 + SELECT *
  39 + from thingsboard.device
  40 + 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
  41 + PRIMARY KEY ( tenant_id, name, id, customer_id, type)
  42 + WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
  43 +
  44 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_and_search_text AS
  45 + SELECT *
  46 + from thingsboard.device
  47 + 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
  48 + PRIMARY KEY ( tenant_id, search_text, id, customer_id, type)
  49 + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC);
  50 +
  51 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_tenant_by_type_and_search_text AS
  52 + SELECT *
  53 + from thingsboard.device
  54 + 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
  55 + PRIMARY KEY ( tenant_id, type, search_text, id, customer_id)
  56 + WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC);
  57 +
  58 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_and_search_text AS
  59 + SELECT *
  60 + from thingsboard.device
  61 + 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
  62 + PRIMARY KEY ( customer_id, tenant_id, search_text, id, type )
  63 + WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC );
  64 +
  65 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_by_customer_by_type_and_search_text AS
  66 + SELECT *
  67 + from thingsboard.device
  68 + 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
  69 + PRIMARY KEY ( customer_id, tenant_id, type, search_text, id )
  70 + WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC );
  71 +
  72 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.device_types_by_tenant AS
  73 + SELECT *
  74 + from thingsboard.device
  75 + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND id IS NOT NULL
  76 + PRIMARY KEY ( (type, tenant_id), id, customer_id)
  77 + WITH CLUSTERING ORDER BY ( id ASC, customer_id DESC);
  78 +
  79 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_tenant_and_name;
  80 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_tenant_and_search_text;
  81 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_tenant_by_type_and_search_text;
  82 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_customer_and_search_text;
  83 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_by_customer_by_type_and_search_text;
  84 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.asset_types_by_tenant;
  85 +
  86 +DROP TABLE IF EXISTS thingsboard.asset;
  87 +
  88 +CREATE TABLE IF NOT EXISTS thingsboard.asset (
  89 + id timeuuid,
  90 + tenant_id timeuuid,
  91 + customer_id timeuuid,
  92 + name text,
  93 + type text,
  94 + search_text text,
  95 + additional_info text,
  96 + PRIMARY KEY (id, tenant_id, customer_id, type)
  97 +);
  98 +
  99 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_name AS
  100 + SELECT *
  101 + from thingsboard.asset
  102 + 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
  103 + PRIMARY KEY ( tenant_id, name, id, customer_id, type)
  104 + WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
  105 +
  106 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_and_search_text AS
  107 + SELECT *
  108 + from thingsboard.asset
  109 + 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
  110 + PRIMARY KEY ( tenant_id, search_text, id, customer_id, type)
  111 + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC, customer_id DESC);
  112 +
  113 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_tenant_by_type_and_search_text AS
  114 + SELECT *
  115 + from thingsboard.asset
  116 + 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
  117 + PRIMARY KEY ( tenant_id, type, search_text, id, customer_id)
  118 + WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC, customer_id DESC);
  119 +
  120 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_and_search_text AS
  121 + SELECT *
  122 + from thingsboard.asset
  123 + 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
  124 + PRIMARY KEY ( customer_id, tenant_id, search_text, id, type )
  125 + WITH CLUSTERING ORDER BY ( tenant_id DESC, search_text ASC, id DESC );
  126 +
  127 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_by_customer_by_type_and_search_text AS
  128 + SELECT *
  129 + from thingsboard.asset
  130 + 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
  131 + PRIMARY KEY ( customer_id, tenant_id, type, search_text, id )
  132 + WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC );
  133 +
  134 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.asset_types_by_tenant AS
  135 + SELECT *
  136 + from thingsboard.asset
  137 + WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND id IS NOT NULL
  138 + PRIMARY KEY ( (type, tenant_id), id, customer_id)
  139 + WITH CLUSTERING ORDER BY ( id ASC, customer_id DESC);
  140 +
  141 +CREATE TABLE IF NOT EXISTS thingsboard.alarm (
  142 + id timeuuid,
  143 + tenant_id timeuuid,
  144 + type text,
  145 + originator_id timeuuid,
  146 + originator_type text,
  147 + severity text,
  148 + status text,
  149 + start_ts bigint,
  150 + end_ts bigint,
  151 + ack_ts bigint,
  152 + clear_ts bigint,
  153 + details text,
  154 + propagate boolean,
  155 + PRIMARY KEY ((tenant_id, originator_id, originator_type), type, id)
  156 +) WITH CLUSTERING ORDER BY ( type ASC, id DESC);
  157 +
  158 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.alarm_by_id AS
  159 + SELECT *
  160 + from thingsboard.alarm
  161 + WHERE tenant_id IS NOT NULL AND originator_id IS NOT NULL AND originator_type IS NOT NULL AND type IS NOT NULL
  162 + AND type IS NOT NULL AND id IS NOT NULL
  163 + PRIMARY KEY (id, tenant_id, originator_id, originator_type, type)
  164 + WITH CLUSTERING ORDER BY ( tenant_id ASC, originator_id ASC, originator_type ASC, type ASC);
  165 +
  166 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.relation_by_type_and_child_type;
  167 +DROP MATERIALIZED VIEW IF EXISTS thingsboard.reverse_relation;
  168 +
  169 +DROP TABLE IF EXISTS thingsboard.relation;
  170 +
  171 +CREATE TABLE IF NOT EXISTS thingsboard.relation (
  172 + from_id timeuuid,
  173 + from_type text,
  174 + to_id timeuuid,
  175 + to_type text,
  176 + relation_type_group text,
  177 + relation_type text,
  178 + additional_info text,
  179 + PRIMARY KEY ((from_id, from_type), relation_type_group, relation_type, to_id, to_type)
  180 +) WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, to_id ASC, to_type ASC);
  181 +
  182 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.relation_by_type_and_child_type AS
  183 + SELECT *
  184 + from thingsboard.relation
  185 + 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
  186 + PRIMARY KEY ((from_id, from_type), relation_type_group, relation_type, to_type, to_id)
  187 + WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, to_type ASC, to_id DESC);
  188 +
  189 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.reverse_relation AS
  190 + SELECT *
  191 + from thingsboard.relation
  192 + 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
  193 + PRIMARY KEY ((to_id, to_type), relation_type_group, relation_type, from_id, from_type)
  194 + WITH CLUSTERING ORDER BY ( relation_type_group ASC, relation_type ASC, from_id ASC, from_type ASC);
... ...
... ... @@ -25,6 +25,7 @@ import org.springframework.context.annotation.Profile;
25 25 import org.springframework.stereotype.Service;
26 26 import org.thingsboard.server.service.component.ComponentDiscoveryService;
27 27 import org.thingsboard.server.service.install.DatabaseSchemaService;
  28 +import org.thingsboard.server.service.install.DatabaseUpgradeService;
28 29 import org.thingsboard.server.service.install.SystemDataLoaderService;
29 30
30 31 import java.nio.file.Files;
... ... @@ -35,6 +36,12 @@ import java.nio.file.Paths;
35 36 @Slf4j
36 37 public class ThingsboardInstallService {
37 38
  39 + @Value("${install.upgrade:false}")
  40 + private Boolean isUpgrade;
  41 +
  42 + @Value("${install.upgrade.from_version:1.2.3}")
  43 + private String upgradeFromVersion;
  44 +
38 45 @Value("${install.data_dir}")
39 46 private String dataDir;
40 47
... ... @@ -45,6 +52,9 @@ public class ThingsboardInstallService {
45 52 private DatabaseSchemaService databaseSchemaService;
46 53
47 54 @Autowired
  55 + private DatabaseUpgradeService databaseUpgradeService;
  56 +
  57 + @Autowired
48 58 private ComponentDiscoveryService componentDiscoveryService;
49 59
50 60 @Autowired
... ... @@ -55,35 +65,67 @@ public class ThingsboardInstallService {
55 65
56 66 public void performInstall() {
57 67 try {
58   - log.info("Starting ThingsBoard Installation...");
  68 + if (isUpgrade) {
  69 + log.info("Starting ThingsBoard Upgrade from version {} ...", upgradeFromVersion);
59 70
60   - if (this.dataDir == null) {
61   - throw new RuntimeException("'install.data_dir' property should specified!");
62   - }
63   - if (!Files.isDirectory(Paths.get(this.dataDir))) {
64   - throw new RuntimeException("'install.data_dir' property value is not a valid directory!");
65   - }
  71 + switch (upgradeFromVersion) {
  72 + case "1.2.3":
  73 + log.info("Upgrading ThingsBoard from version {} to 1.3.0 ...", upgradeFromVersion);
  74 +
  75 + databaseUpgradeService.upgradeDatabase(upgradeFromVersion);
  76 +
  77 + log.info("Updating system data...");
66 78
67   - log.info("Installing DataBase schema...");
  79 + systemDataLoaderService.deleteSystemWidgetBundle("charts");
  80 + systemDataLoaderService.deleteSystemWidgetBundle("cards");
  81 + systemDataLoaderService.deleteSystemWidgetBundle("maps");
  82 + systemDataLoaderService.deleteSystemWidgetBundle("analogue_gauges");
  83 + systemDataLoaderService.deleteSystemWidgetBundle("digital_gauges");
  84 + systemDataLoaderService.deleteSystemWidgetBundle("gpio_widgets");
  85 + systemDataLoaderService.deleteSystemWidgetBundle("alarm_widgets");
68 86
69   - databaseSchemaService.createDatabaseSchema();
  87 + systemDataLoaderService.loadSystemWidgets();
70 88
71   - log.info("Loading system data...");
  89 + break;
  90 + default:
  91 + throw new RuntimeException("Unable to upgrade ThingsBoard, unsupported fromVersion: " + upgradeFromVersion);
72 92
73   - componentDiscoveryService.discoverComponents();
  93 + }
  94 + log.info("Upgrade finished successfully!");
74 95
75   - systemDataLoaderService.createSysAdmin();
76   - systemDataLoaderService.createAdminSettings();
77   - systemDataLoaderService.loadSystemWidgets();
78   - systemDataLoaderService.loadSystemPlugins();
79   - systemDataLoaderService.loadSystemRules();
  96 + } else {
80 97
81   - if (loadDemo) {
82   - log.info("Loading demo data...");
83   - systemDataLoaderService.loadDemoData();
  98 + log.info("Starting ThingsBoard Installation...");
  99 +
  100 + if (this.dataDir == null) {
  101 + throw new RuntimeException("'install.data_dir' property should specified!");
  102 + }
  103 + if (!Files.isDirectory(Paths.get(this.dataDir))) {
  104 + throw new RuntimeException("'install.data_dir' property value is not a valid directory!");
  105 + }
  106 +
  107 + log.info("Installing DataBase schema...");
  108 +
  109 + databaseSchemaService.createDatabaseSchema();
  110 +
  111 + log.info("Loading system data...");
  112 +
  113 + componentDiscoveryService.discoverComponents();
  114 +
  115 + systemDataLoaderService.createSysAdmin();
  116 + systemDataLoaderService.createAdminSettings();
  117 + systemDataLoaderService.loadSystemWidgets();
  118 + systemDataLoaderService.loadSystemPlugins();
  119 + systemDataLoaderService.loadSystemRules();
  120 +
  121 + if (loadDemo) {
  122 + log.info("Loading demo data...");
  123 + systemDataLoaderService.loadDemoData();
  124 + }
  125 + log.info("Installation finished successfully!");
84 126 }
85 127
86   - log.info("Finished!");
  128 +
87 129 } catch (Exception e) {
88 130 log.error("Unexpected error during ThingsBoard installation!", e);
89 131 throw new ThingsboardInstallException("Unexpected error during ThingsBoard installation!", e);
... ...
... ... @@ -23,7 +23,7 @@ import org.springframework.context.annotation.Profile;
23 23 import org.springframework.stereotype.Service;
24 24 import org.thingsboard.server.dao.cassandra.CassandraInstallCluster;
25 25 import org.thingsboard.server.dao.util.NoSqlDao;
26   -import org.thingsboard.server.install.cql.CQLStatementsParser;
  26 +import org.thingsboard.server.service.install.cql.CQLStatementsParser;
27 27
28 28 import java.nio.file.Path;
29 29 import java.nio.file.Paths;
... ... @@ -35,6 +35,7 @@ import java.util.List;
35 35 @Slf4j
36 36 public class CassandraDatabaseSchemaService implements DatabaseSchemaService {
37 37
  38 + private static final String CASSANDRA_DIR = "cassandra";
38 39 private static final String SCHEMA_CQL = "schema.cql";
39 40
40 41 @Value("${install.data_dir}")
... ... @@ -47,7 +48,7 @@ public class CassandraDatabaseSchemaService implements DatabaseSchemaService {
47 48 public void createDatabaseSchema() throws Exception {
48 49 log.info("Installing Cassandra DataBase schema...");
49 50
50   - Path schemaFile = Paths.get(this.dataDir, SCHEMA_CQL);
  51 + Path schemaFile = Paths.get(this.dataDir, CASSANDRA_DIR, SCHEMA_CQL);
51 52 loadCql(schemaFile);
52 53
53 54 }
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.service.install;
  18 +
  19 +import com.datastax.driver.core.KeyspaceMetadata;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.beans.factory.annotation.Value;
  23 +import org.springframework.context.annotation.Profile;
  24 +import org.springframework.stereotype.Service;
  25 +import org.thingsboard.server.dao.cassandra.CassandraCluster;
  26 +import org.thingsboard.server.dao.cassandra.CassandraInstallCluster;
  27 +import org.thingsboard.server.dao.util.NoSqlDao;
  28 +import org.thingsboard.server.service.install.cql.CQLStatementsParser;
  29 +import org.thingsboard.server.service.install.cql.CassandraDbHelper;
  30 +
  31 +import java.nio.file.Files;
  32 +import java.nio.file.Path;
  33 +import java.nio.file.Paths;
  34 +import java.util.List;
  35 +
  36 +@Service
  37 +@NoSqlDao
  38 +@Profile("install")
  39 +@Slf4j
  40 +public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
  41 +
  42 + private static final String SCHEMA_UPDATE_CQL = "schema_update.cql";
  43 +
  44 + @Value("${install.data_dir}")
  45 + private String dataDir;
  46 +
  47 + @Autowired
  48 + private CassandraCluster cluster;
  49 +
  50 + @Autowired
  51 + private CassandraInstallCluster installCluster;
  52 +
  53 + @Override
  54 + public void upgradeDatabase(String fromVersion) throws Exception {
  55 +
  56 + switch (fromVersion) {
  57 + case "1.2.3":
  58 +
  59 + log.info("Upgrading Cassandara DataBase from version {} to 1.3.0 ...", fromVersion);
  60 +
  61 + //Dump devices, assets and relations
  62 +
  63 + KeyspaceMetadata ks = cluster.getCluster().getMetadata().getKeyspace(cluster.getKeyspaceName());
  64 +
  65 + log.info("Dumping devices ...");
  66 + Path devicesDump = CassandraDbHelper.dumpCfIfExists(ks, cluster.getSession(), "device",
  67 + new String[]{"id", "tenant_id", "customer_id", "name", "search_text", "additional_info"},
  68 + "tb-devices");
  69 + if (devicesDump != null) {
  70 + CassandraDbHelper.appendToEndOfLine(devicesDump, "default");
  71 + }
  72 + log.info("Devices dumped.");
  73 +
  74 + log.info("Dumping assets ...");
  75 + Path assetsDump = CassandraDbHelper.dumpCfIfExists(ks, cluster.getSession(), "asset",
  76 + new String[]{"id", "tenant_id", "customer_id", "name", "search_text", "additional_info", "type"},
  77 + "tb-assets");
  78 + log.info("Assets dumped.");
  79 +
  80 + log.info("Dumping relations ...");
  81 + Path relationsDump = CassandraDbHelper.dumpCfIfExists(ks, cluster.getSession(), "relation",
  82 + new String[]{"from_id", "from_type", "to_id", "to_type", "relation_type", "additional_info"},
  83 + "tb-relations");
  84 + if (relationsDump != null) {
  85 + CassandraDbHelper.appendToEndOfLine(relationsDump, "COMMON");
  86 + }
  87 + log.info("Relations dumped.");
  88 +
  89 + log.info("Updating schema ...");
  90 + Path schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.3.0", SCHEMA_UPDATE_CQL);
  91 + loadCql(schemaUpdateFile);
  92 + log.info("Schema updated.");
  93 +
  94 + //Restore devices, assets and relations
  95 +
  96 + log.info("Restoring devices ...");
  97 + if (devicesDump != null) {
  98 + CassandraDbHelper.loadCf(ks, cluster.getSession(), "device",
  99 + new String[]{"id", "tenant_id", "customer_id", "name", "search_text", "additional_info", "type"}, devicesDump);
  100 + Files.deleteIfExists(devicesDump);
  101 + }
  102 + log.info("Devices restored.");
  103 +
  104 + log.info("Restoring assets ...");
  105 + if (assetsDump != null) {
  106 + CassandraDbHelper.loadCf(ks, cluster.getSession(), "asset",
  107 + new String[]{"id", "tenant_id", "customer_id", "name", "search_text", "additional_info", "type"}, assetsDump);
  108 + Files.deleteIfExists(assetsDump);
  109 + }
  110 + log.info("Assets restored.");
  111 +
  112 + log.info("Restoring relations ...");
  113 + if (relationsDump != null) {
  114 + CassandraDbHelper.loadCf(ks, cluster.getSession(), "relation",
  115 + new String[]{"from_id", "from_type", "to_id", "to_type", "relation_type", "additional_info", "relation_type_group"}, relationsDump);
  116 + Files.deleteIfExists(relationsDump);
  117 + }
  118 + log.info("Relations restored.");
  119 +
  120 + break;
  121 + default:
  122 + throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion);
  123 + }
  124 +
  125 + }
  126 +
  127 + private void loadCql(Path cql) throws Exception {
  128 + List<String> statements = new CQLStatementsParser(cql).getStatements();
  129 + statements.forEach(statement -> installCluster.getSession().execute(statement));
  130 + }
  131 +
  132 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.service.install;
  18 +
  19 +public interface DatabaseUpgradeService {
  20 +
  21 + void upgradeDatabase(String fromVersion) throws Exception;
  22 +
  23 +}
... ...
... ... @@ -41,6 +41,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
41 41 import org.thingsboard.server.dao.dashboard.DashboardService;
42 42 import org.thingsboard.server.dao.device.DeviceCredentialsService;
43 43 import org.thingsboard.server.dao.device.DeviceService;
  44 +import org.thingsboard.server.dao.model.ModelConstants;
44 45 import org.thingsboard.server.dao.plugin.PluginService;
45 46 import org.thingsboard.server.dao.rule.RuleService;
46 47 import org.thingsboard.server.dao.settings.AdminSettingsService;
... ... @@ -227,6 +228,14 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
227 228 loadDashboards(Paths.get(dataDir, JSON_DIR, DEMO_DIR, DASHBOARDS_DIR), demoTenant.getId(), null);
228 229 }
229 230
  231 + @Override
  232 + public void deleteSystemWidgetBundle(String bundleAlias) throws Exception {
  233 + WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(new TenantId(ModelConstants.NULL_UUID), bundleAlias);
  234 + if (widgetsBundle != null) {
  235 + widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getId());
  236 + }
  237 + }
  238 +
230 239 private User createUser(Authority authority,
231 240 TenantId tenantId,
232 241 CustomerId customerId,
... ...
... ... @@ -22,20 +22,44 @@ import org.springframework.context.annotation.Profile;
22 22 import org.springframework.stereotype.Service;
23 23 import org.thingsboard.server.dao.util.SqlDao;
24 24
  25 +import java.nio.charset.Charset;
  26 +import java.nio.file.Files;
  27 +import java.nio.file.Path;
  28 +import java.nio.file.Paths;
  29 +import java.sql.Connection;
  30 +import java.sql.DriverManager;
  31 +
25 32 @Service
26 33 @Profile("install")
27 34 @Slf4j
28 35 @SqlDao
29 36 public class SqlDatabaseSchemaService implements DatabaseSchemaService {
30 37
  38 + private static final String SQL_DIR = "sql";
  39 + private static final String SCHEMA_SQL = "schema.sql";
  40 +
31 41 @Value("${install.data_dir}")
32 42 private String dataDir;
33 43
  44 + @Value("${spring.datasource.url}")
  45 + private String dbUrl;
  46 +
  47 + @Value("${spring.datasource.username}")
  48 + private String dbUserName;
  49 +
  50 + @Value("${spring.datasource.password}")
  51 + private String dbPassword;
  52 +
34 53 @Override
35 54 public void createDatabaseSchema() throws Exception {
36 55
37 56 log.info("Installing SQL DataBase schema...");
38   - //TODO:
  57 +
  58 + Path schemaFile = Paths.get(this.dataDir, SQL_DIR, SCHEMA_SQL);
  59 + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
  60 + String sql = new String(Files.readAllBytes(schemaFile), Charset.forName("UTF-8"));
  61 + conn.createStatement().execute(sql);
  62 + }
39 63
40 64 }
41 65
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.service.install;
  18 +
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.context.annotation.Profile;
  21 +import org.springframework.stereotype.Service;
  22 +import org.thingsboard.server.dao.util.SqlDao;
  23 +
  24 +@Service
  25 +@Profile("install")
  26 +@Slf4j
  27 +@SqlDao
  28 +public class SqlDatabaseUpgradeService implements DatabaseUpgradeService {
  29 +
  30 + @Override
  31 + public void upgradeDatabase(String fromVersion) throws Exception {
  32 + switch (fromVersion) {
  33 + default:
  34 + throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
  35 + }
  36 + }
  37 +}
... ...
... ... @@ -29,4 +29,6 @@ public interface SystemDataLoaderService {
29 29
30 30 void loadDemoData() throws Exception;
31 31
  32 + void deleteSystemWidgetBundle(String bundleAlias) throws Exception;
  33 +
32 34 }
... ...
application/src/main/java/org/thingsboard/server/service/install/cql/CQLStatementsParser.java renamed from application/src/main/java/org/thingsboard/server/install/cql/CQLStatementsParser.java
... ... @@ -14,7 +14,7 @@
14 14 * limitations under the License.
15 15 */
16 16
17   -package org.thingsboard.server.install.cql;
  17 +package org.thingsboard.server.service.install.cql;
18 18
19 19 import lombok.extern.slf4j.Slf4j;
20 20
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.service.install.cql;
  18 +
  19 +import com.datastax.driver.core.*;
  20 +import org.apache.commons.csv.CSVFormat;
  21 +import org.apache.commons.csv.CSVParser;
  22 +import org.apache.commons.csv.CSVPrinter;
  23 +import org.apache.commons.csv.CSVRecord;
  24 +
  25 +import java.io.IOException;
  26 +import java.nio.file.Files;
  27 +import java.nio.file.Path;
  28 +import java.nio.file.StandardCopyOption;
  29 +import java.util.*;
  30 +
  31 +public class CassandraDbHelper {
  32 +
  33 + private static final CSVFormat CSV_DUMP_FORMAT = CSVFormat.DEFAULT.withNullString("\\N");
  34 +
  35 + public static Path dumpCfIfExists(KeyspaceMetadata ks, Session session, String cfName,
  36 + String[] columns, String dumpPrefix) throws Exception {
  37 + if (ks.getTable(cfName) != null) {
  38 + Path dumpFile = Files.createTempFile(dumpPrefix, null);
  39 + Files.deleteIfExists(dumpFile);
  40 + try (CSVPrinter csvPrinter = new CSVPrinter(Files.newBufferedWriter(dumpFile), CSV_DUMP_FORMAT)) {
  41 + Statement stmt = new SimpleStatement("SELECT * FROM " + cfName);
  42 + stmt.setFetchSize(1000);
  43 + ResultSet rs = session.execute(stmt);
  44 + Iterator<Row> iter = rs.iterator();
  45 + while (iter.hasNext()) {
  46 + Row row = iter.next();
  47 + if (row != null) {
  48 + dumpRow(row, columns, csvPrinter);
  49 + }
  50 + }
  51 + }
  52 + return dumpFile;
  53 + } else {
  54 + return null;
  55 + }
  56 + }
  57 +
  58 + public static void appendToEndOfLine(Path targetDumpFile, String toAppend) throws Exception {
  59 + Path tmp = Files.createTempFile(null, null);
  60 + try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(targetDumpFile), CSV_DUMP_FORMAT)) {
  61 + try (CSVPrinter csvPrinter = new CSVPrinter(Files.newBufferedWriter(tmp), CSV_DUMP_FORMAT)) {
  62 + csvParser.forEach(record -> {
  63 + List<String> newRecord = new ArrayList<>();
  64 + record.forEach(val -> newRecord.add(val));
  65 + newRecord.add(toAppend);
  66 + try {
  67 + csvPrinter.printRecord(newRecord);
  68 + } catch (IOException e) {
  69 + throw new RuntimeException("Error appending to EOL", e);
  70 + }
  71 + });
  72 + }
  73 + }
  74 + Files.move(tmp, targetDumpFile, StandardCopyOption.REPLACE_EXISTING);
  75 + }
  76 +
  77 + public static void loadCf(KeyspaceMetadata ks, Session session, String cfName, String[] columns, Path sourceFile) throws Exception {
  78 + TableMetadata tableMetadata = ks.getTable(cfName);
  79 + PreparedStatement prepared = session.prepare(createInsertStatement(cfName, columns));
  80 + try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(sourceFile), CSV_DUMP_FORMAT.withHeader(columns))) {
  81 + csvParser.forEach(record -> {
  82 + BoundStatement boundStatement = prepared.bind();
  83 + for (String column : columns) {
  84 + setColumnValue(tableMetadata, column, record, boundStatement);
  85 + }
  86 + session.execute(boundStatement);
  87 + });
  88 + }
  89 + }
  90 +
  91 +
  92 + private static void dumpRow(Row row, String[] columns, CSVPrinter csvPrinter) throws Exception {
  93 + List<String> record = new ArrayList<>();
  94 + for (String column : columns) {
  95 + record.add(getColumnValue(column, row));
  96 + }
  97 + csvPrinter.printRecord(record);
  98 + }
  99 +
  100 + private static String getColumnValue(String column, Row row) {
  101 + String str = "";
  102 + int index = row.getColumnDefinitions().getIndexOf(column);
  103 + if (index > -1) {
  104 + DataType type = row.getColumnDefinitions().getType(index);
  105 + try {
  106 + if (row.isNull(index)) {
  107 + return null;
  108 + } else if (type == DataType.cdouble()) {
  109 + str = new Double(row.getDouble(index)).toString();
  110 + } else if (type == DataType.cint()) {
  111 + str = new Integer(row.getInt(index)).toString();
  112 + } else if (type == DataType.uuid()) {
  113 + str = row.getUUID(index).toString();
  114 + } else if (type == DataType.timeuuid()) {
  115 + str = row.getUUID(index).toString();
  116 + } else if (type == DataType.cfloat()) {
  117 + str = new Float(row.getFloat(index)).toString();
  118 + } else if (type == DataType.timestamp()) {
  119 + str = ""+row.getTimestamp(index).getTime();
  120 + } else {
  121 + str = row.getString(index);
  122 + }
  123 + } catch (Exception e) {
  124 + str = "";
  125 + }
  126 + }
  127 + return str;
  128 + }
  129 +
  130 + private static String createInsertStatement(String cfName, String[] columns) {
  131 + StringBuilder insertStatementBuilder = new StringBuilder();
  132 + insertStatementBuilder.append("INSERT INTO ").append(cfName).append(" (");
  133 + for (String column : columns) {
  134 + insertStatementBuilder.append(column).append(",");
  135 + }
  136 + insertStatementBuilder.deleteCharAt(insertStatementBuilder.length() - 1);
  137 + insertStatementBuilder.append(") VALUES (");
  138 + for (String column : columns) {
  139 + insertStatementBuilder.append("?").append(",");
  140 + }
  141 + insertStatementBuilder.deleteCharAt(insertStatementBuilder.length() - 1);
  142 + insertStatementBuilder.append(")");
  143 + return insertStatementBuilder.toString();
  144 + }
  145 +
  146 + private static void setColumnValue(TableMetadata tableMetadata, String column,
  147 + CSVRecord record, BoundStatement boundStatement) {
  148 + String value = record.get(column);
  149 + DataType type = tableMetadata.getColumn(column).getType();
  150 + if (value == null) {
  151 + boundStatement.setToNull(column);
  152 + } else if (type == DataType.cdouble()) {
  153 + boundStatement.setDouble(column, Double.valueOf(value));
  154 + } else if (type == DataType.cint()) {
  155 + boundStatement.setInt(column, Integer.valueOf(value));
  156 + } else if (type == DataType.uuid()) {
  157 + boundStatement.setUUID(column, UUID.fromString(value));
  158 + } else if (type == DataType.timeuuid()) {
  159 + boundStatement.setUUID(column, UUID.fromString(value));
  160 + } else if (type == DataType.cfloat()) {
  161 + boundStatement.setFloat(column, Float.valueOf(value));
  162 + } else if (type == DataType.timestamp()) {
  163 + boundStatement.setTimestamp(column, new Date(Long.valueOf(value)));
  164 + } else {
  165 + boundStatement.setString(column, value);
  166 + }
  167 + }
  168 +
  169 +}
... ...
  1 +#!/bin/bash
  2 +#
  3 +# Copyright © 2016-2017 The Thingsboard Authors
  4 +#
  5 +# Licensed under the Apache License, Version 2.0 (the "License");
  6 +# you may not use this file except in compliance with the License.
  7 +# You may obtain a copy of the License at
  8 +#
  9 +# http://www.apache.org/licenses/LICENSE-2.0
  10 +#
  11 +# Unless required by applicable law or agreed to in writing, software
  12 +# distributed under the License is distributed on an "AS IS" BASIS,
  13 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 +# See the License for the specific language governing permissions and
  15 +# limitations under the License.
  16 +#
  17 +
  18 +while [[ $# -gt 0 ]]
  19 +do
  20 +key="$1"
  21 +
  22 +case $key in
  23 + --loadDemo)
  24 + LOAD_DEMO=true
  25 + shift # past argument
  26 + ;;
  27 + *)
  28 + # unknown option
  29 + ;;
  30 +esac
  31 +shift # past argument or value
  32 +done
  33 +
  34 +if [ "$LOAD_DEMO" == "true" ]; then
  35 + loadDemo=true
  36 +else
  37 + loadDemo=false
  38 +fi
  39 +
  40 +CONF_FOLDER=${pkg.installFolder}/conf
  41 +configfile=${pkg.name}.conf
  42 +jarfile=${pkg.installFolder}/bin/${pkg.name}.jar
  43 +installDir=${pkg.installFolder}/data
  44 +
  45 +source "${CONF_FOLDER}/${configfile}"
  46 +
  47 +run_user=${pkg.name}
  48 +
  49 +su -s /bin/sh -c "java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \
  50 + -Dinstall.data_dir=${installDir} \
  51 + -Dinstall.load_demo=${loadDemo} \
  52 + -Dspring.jpa.hibernate.ddl-auto=none \
  53 + -Dinstall.upgrade=false \
  54 + -Dlogging.config=${pkg.installFolder}/bin/install/logback.xml \
  55 + org.springframework.boot.loader.PropertiesLauncher" "$run_user"
  56 +
  57 +if [ $? -ne 0 ]; then
  58 + echo "ThingsBoard installation failed!"
  59 +else
  60 + echo "ThingsBoard installed successfully!"
  61 +fi
  62 +
  63 +exit $?
... ...
  1 +<?xml version="1.0" encoding="UTF-8" ?>
  2 +<!--
  3 +
  4 + Copyright © 2016-2017 The Thingsboard Authors
  5 +
  6 + Licensed under the Apache License, Version 2.0 (the "License");
  7 + you may not use this file except in compliance with the License.
  8 + You may obtain a copy of the License at
  9 +
  10 + http://www.apache.org/licenses/LICENSE-2.0
  11 +
  12 + Unless required by applicable law or agreed to in writing, software
  13 + distributed under the License is distributed on an "AS IS" BASIS,
  14 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + See the License for the specific language governing permissions and
  16 + limitations under the License.
  17 +
  18 +-->
  19 +<!DOCTYPE configuration>
  20 +<configuration>
  21 +
  22 + <appender name="fileLogAppender"
  23 + class="ch.qos.logback.core.rolling.RollingFileAppender">
  24 + <file>${pkg.logFolder}/install.log</file>
  25 + <rollingPolicy
  26 + class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
  27 + <fileNamePattern>${pkg.logFolder}/install.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  28 + <maxFileSize>100MB</maxFileSize>
  29 + <maxHistory>30</maxHistory>
  30 + <totalSizeCap>3GB</totalSizeCap>
  31 + </rollingPolicy>
  32 + <encoder>
  33 + <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
  34 + </encoder>
  35 + </appender>
  36 +
  37 + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  38 + <encoder>
  39 + <pattern>%msg%n</pattern>
  40 + </encoder>
  41 + </appender>
  42 +
  43 + <logger name="org.thingsboard.server.install" level="INFO">
  44 + <appender-ref ref="STDOUT" />
  45 + </logger>
  46 +
  47 + <logger name="org.thingsboard.server.service.install" level="INFO">
  48 + <appender-ref ref="STDOUT" />
  49 + </logger>
  50 +
  51 + <logger name="org.thingsboard.server" level="INFO" />
  52 + <logger name="akka" level="INFO" />
  53 +
  54 + <root level="INFO">
  55 + <appender-ref ref="fileLogAppender"/>
  56 + </root>
  57 +
  58 +</configuration>
... ...
  1 +#!/bin/bash
  2 +#
  3 +# Copyright © 2016-2017 The Thingsboard Authors
  4 +#
  5 +# Licensed under the Apache License, Version 2.0 (the "License");
  6 +# you may not use this file except in compliance with the License.
  7 +# You may obtain a copy of the License at
  8 +#
  9 +# http://www.apache.org/licenses/LICENSE-2.0
  10 +#
  11 +# Unless required by applicable law or agreed to in writing, software
  12 +# distributed under the License is distributed on an "AS IS" BASIS,
  13 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 +# See the License for the specific language governing permissions and
  15 +# limitations under the License.
  16 +#
  17 +
  18 +for i in "$@"
  19 +do
  20 +case $i in
  21 + --fromVersion=*)
  22 + FROM_VERSION="${i#*=}"
  23 + shift
  24 + ;;
  25 + *)
  26 + # unknown option
  27 + ;;
  28 +esac
  29 +done
  30 +
  31 +if [[ -z "${FROM_VERSION// }" ]]; then
  32 + echo "--fromVersion parameter is invalid or unspecified!"
  33 + echo "Usage: upgrade.sh --fromVersion={VERSION}"
  34 + exit 1
  35 +else
  36 + fromVersion="${FROM_VERSION// }"
  37 +fi
  38 +
  39 +CONF_FOLDER=${pkg.installFolder}/conf
  40 +configfile=${pkg.name}.conf
  41 +jarfile=${pkg.installFolder}/bin/${pkg.name}.jar
  42 +installDir=${pkg.installFolder}/data
  43 +
  44 +source "${CONF_FOLDER}/${configfile}"
  45 +
  46 +run_user=${pkg.name}
  47 +
  48 +su -s /bin/sh -c "java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \
  49 + -Dinstall.data_dir=${installDir} \
  50 + -Dspring.jpa.hibernate.ddl-auto=none \
  51 + -Dinstall.upgrade=true \
  52 + -Dinstall.upgrade.from_version=${fromVersion} \
  53 + -Dlogging.config=${pkg.installFolder}/bin/install/logback.xml \
  54 + org.springframework.boot.loader.PropertiesLauncher" "$run_user"
  55 +
  56 +if [ $? -ne 0 ]; then
  57 + echo "ThingsBoard upgrade failed!"
  58 +else
  59 + echo "ThingsBoard upgraded successfully!"
  60 +fi
  61 +
  62 +exit $?
... ...
... ... @@ -127,6 +127,10 @@ public abstract class AbstractCassandraCluster {
127 127 }
128 128 }
129 129
  130 + public String getKeyspaceName() {
  131 + return keyspaceName;
  132 + }
  133 +
130 134 private boolean isInstall() {
131 135 return environment.acceptsProfiles("install");
132 136 }
... ...
... ... @@ -46,6 +46,8 @@
46 46 <guava.version>18.0</guava.version>
47 47 <commons-lang3.version>3.4</commons-lang3.version>
48 48 <commons-validator.version>1.5.0</commons-validator.version>
  49 + <commons-io.version>2.5</commons-io.version>
  50 + <commons-csv.version>1.4</commons-csv.version>
49 51 <jackson.version>2.8.8.1</jackson.version>
50 52 <json-schema-validator.version>2.2.6</json-schema-validator.version>
51 53 <scala.version>2.11</scala.version>
... ... @@ -566,6 +568,16 @@
566 568 <version>${commons-validator.version}</version>
567 569 </dependency>
568 570 <dependency>
  571 + <groupId>commons-io</groupId>
  572 + <artifactId>commons-io</artifactId>
  573 + <version>${commons-io.version}</version>
  574 + </dependency>
  575 + <dependency>
  576 + <groupId>org.apache.commons</groupId>
  577 + <artifactId>commons-csv</artifactId>
  578 + <version>${commons-csv.version}</version>
  579 + </dependency>
  580 + <dependency>
569 581 <groupId>com.fasterxml.jackson.core</groupId>
570 582 <artifactId>jackson-databind</artifactId>
571 583 <version>${jackson.version}</version>
... ...