2 * ============LICENSE_START=======================================================
3 * ONAP : ccsdk features
4 * ================================================================================
5 * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.database;
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.nio.charset.StandardCharsets;
28 import java.nio.file.Files;
29 import java.sql.SQLException;
30 import java.text.ParseException;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
35 import org.onap.ccsdk.features.sdnr.wt.common.database.SearchHit;
36 import org.onap.ccsdk.features.sdnr.wt.common.database.SearchResult;
37 import org.onap.ccsdk.features.sdnr.wt.common.database.data.AliasesEntry;
38 import org.onap.ccsdk.features.sdnr.wt.common.database.data.AliasesEntryList;
39 import org.onap.ccsdk.features.sdnr.wt.common.database.data.DatabaseVersion;
40 import org.onap.ccsdk.features.sdnr.wt.common.database.data.IndicesEntry;
41 import org.onap.ccsdk.features.sdnr.wt.common.database.data.IndicesEntryList;
42 import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.SqlDBClient;
43 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.SdnrDbType;
44 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.DataMigrationProviderService;
45 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.ReleaseInformation;
46 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ComponentData;
47 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ComponentName;
48 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DataContainer;
49 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.DataMigrationReport;
50 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.Release;
51 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.ReleaseGroup;
52 import org.onap.ccsdk.features.sdnr.wt.dataprovider.setup.data.SearchHitConverter;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 public class MariaDbDataMigrationProvider implements DataMigrationProviderService {
59 private static final Logger LOG = LoggerFactory.getLogger(MariaDbDataMigrationProvider.class);
60 private static final SdnrDbType DBTYPE = SdnrDbType.MARIADB;
61 private static final String LOG_DELETING_INDEX = "deleting index {}";
62 private final SqlDBClient dbClient;
64 public MariaDbDataMigrationProvider(String url, String username, String password, boolean trustAll,
65 long timeoutms) throws Exception {
66 dbClient = new SqlDBClient(url, username, password);
70 public DataMigrationReport importData(String filename, boolean dryrun) throws Exception {
71 return this.importData(filename, dryrun, Release.CURRENT_RELEASE);
75 public DataMigrationReport importData(String filename, boolean dryrun, Release forRelease) throws Exception {
76 DataMigrationReport report = new DataMigrationReport();
77 File file = new File(filename);
80 report.error("file %s not found", filename);
83 throw new FileNotFoundException(filename);
85 DataContainer container = null;
87 container = DataContainer.load(file);
88 } catch (Exception e) {
90 report.error("problem loading file %s: %s", filename, e.getMessage());
93 throw new Exception("problem loading file " + filename, e);
95 ReleaseInformation ri = ReleaseInformation.getInstance(forRelease);
96 SearchHitConverter converter;
97 Set<ComponentName> components = ri.getComponents();
98 //for all db components of dest architecture
99 for (ComponentName component : components) {
100 //convert to ComponentData for current release with existing ComponentData of the container
101 converter = SearchHitConverter.Factory.getInstance(container.getRelease(), forRelease, component);
102 if (converter == null) {
105 ComponentData data = converter.convert(container);
107 String indexName = ri.getAlias(component);
108 String dataTypeName = ri.getDataType(component);
110 report.log("write %d entries into %s/%s", data.size(), indexName, dataTypeName);
112 LOG.debug("write {} entries into {}/{}", data.size(), indexName, dataTypeName);
114 for (SearchHit item : data) {
116 String id = null;//this.dbClient.doWriteRaw(indexName, dataTypeName, item.getId(), item.getSourceAsString(), true);
117 if (!item.getId().equals(id)) {
118 LOG.warn("entry for {} with original id {} was written with another id {}",
119 component.getValue(), item.getId(), id);
125 report.error("unable to convert data for " + component.getValue() + " from version "
126 + container.getRelease().getValue() + " to " + forRelease.getValue() + "\n");
128 LOG.warn("unable to convert data for {} from version {} to {}", component.getValue(),
129 container.getRelease().getValue(), forRelease.getValue());
133 LOG.info("import of {} completed", filename);
135 report.log("import of %s completed", filename);
137 report.setCompleted(true);
143 * export data if file exists .1 (.n) will be created
147 public DataMigrationReport exportData(String filename) {
148 DataMigrationReport report = new DataMigrationReport();
150 DataContainer container = new DataContainer();
152 filename = this.checkFilenameForWrite(filename);
153 LOG.info("output will be written to {}", filename);
155 Release dbRelease = this.autoDetectRelease();
156 if (dbRelease == null) {
157 report.error("unbable to detect db release. is database initialized?");
160 ReleaseInformation ri = ReleaseInformation.getInstance(dbRelease);
161 boolean componentsSucceeded = true;
162 for (ComponentName c : ri.getComponents()) {
163 ComponentData data = new ComponentData(c);
164 // TODO : check why doReadAllJsonData are comment
165 //SearchResult<SearchHit> result = null;//this.dbClient.doReadAllJsonData(ri.getAlias(c), ri.getDataType(c), false);
166 //data.addAll(result.getHits());
167 container.addComponent(c, data);
170 Files.write(new File(filename).toPath(), Arrays.asList(container.toJSON()), StandardCharsets.UTF_8);
171 report.setCompleted(componentsSucceeded);
172 } catch (IOException e) {
173 LOG.warn("problem writing data to {}: {}", filename, e);
178 private String checkFilenameForWrite(String filename) {
179 File f = new File(filename);
183 return this.checkFilenameForWrite(filename, 0);
186 private String checkFilenameForWrite(String filename, int apdx) {
187 File f = new File(String.format("$s.$d", filename, apdx));
191 return this.checkFilenameForWrite(filename, apdx + 1);
195 public Release getCurrentVersion() {
196 return Release.CURRENT_RELEASE;
201 public Release autoDetectRelease() {
202 DatabaseVersion dbVersion;
204 dbVersion = this.dbClient.readActualVersion();
205 } catch (SQLException | ParseException e) {
206 LOG.error("unable to detect db version", e);
209 AliasesEntryList aliases = this.dbClient.readViews();
210 IndicesEntryList indices = this.dbClient.readTables();
211 if (indices == null) {
214 List<Release> foundReleases = new ArrayList<>();
215 //if there are active aliases reduce indices to the active ones
216 if (aliases != null && !aliases.isEmpty()) {
217 indices = indices.subList(aliases.getLinkedIndices());
219 for (Release r : Release.values()) {
220 if (r.isDbInRange(dbVersion, SdnrDbType.MARIADB)) {
221 ReleaseInformation ri = ReleaseInformation.getInstance(r);
222 if (ri != null && ri.containsIndices(indices)) {
223 foundReleases.add(r);
227 if (foundReleases.size() == 1) {
228 return foundReleases.get(0);
230 LOG.error("detect {} releases: {}. unable to detect for which one to do sth.", foundReleases.size(),
236 public boolean initDatabase(Release release, int numShards, int numReplicas, String dbPrefix, boolean forceRecreate,
239 this.dbClient.waitForYellowStatus(timeoutms);
241 DatabaseVersion dbVersion;
243 dbVersion = this.dbClient.readActualVersion();
244 } catch (SQLException | ParseException e1) {
245 LOG.error("unable to detect db version", e1);
248 if (dbVersion == null) {
251 LOG.info("detected database version {}", dbVersion);
252 if (release == null) {
253 release = ReleaseGroup.CURRENT_RELEASE.getLatestCompatibleRelease(dbVersion, SdnrDbType.MARIADB);
254 if (release == null) {
255 LOG.warn("unable to autodetect release for this database version for release {}",
256 ReleaseGroup.CURRENT_RELEASE.name());
259 LOG.info("autodetect release {}", release);
261 if (!release.isDbInRange(dbVersion, SdnrDbType.MARIADB)) {
262 LOG.warn("db version {} maybe not compatible with release {}", dbVersion, release);
266 this.clearDatabase(release, dbPrefix, 0);
268 ReleaseInformation ri = ReleaseInformation.getInstance(release);
269 AliasesEntryList views = this.dbClient.readViews();
270 IndicesEntryList indices = this.dbClient.readTables();
271 if (views == null || indices == null) {
274 boolean response = false;
275 if (!ri.runPreInitCommands(this.dbClient)) {
278 for (ComponentName component : ri.getComponents()) {
280 if (ri.hasOwnDbIndex(component)) {
281 //check if index already exists
282 String tableName = ri.getIndex(component, dbPrefix);
283 String viewName = ri.getAlias(component, dbPrefix);
284 if (indices.findByIndex(tableName) == null) {
285 LOG.info("creating index for {}", component);
286 response = this.dbClient.createTable(ri.getIndex(component, dbPrefix), ri.getDatabaseMapping(component, DBTYPE));
287 LOG.info(response ? "succeeded" : "failed");
289 LOG.info("index {} for {} already exists", tableName, component);
291 //check if alias already exists
292 if (views.findByAlias(viewName) == null) {
293 LOG.info("creating alias for {}", component);
294 response = this.dbClient.createView(tableName, viewName);
295 LOG.info(response ? "succeeded" : "failed");
297 LOG.info("view {} for table {} for {} already exists", viewName, tableName, component);
300 } catch (SQLException e) {
301 LOG.error(e.getMessage());
305 if (!ri.runPostInitCommands(this.dbClient)) {
312 public boolean clearDatabase(Release release, String dbPrefix, long timeoutms) {
315 this.dbClient.waitForYellowStatus(timeoutms);
318 AliasesEntryList entries = this.dbClient.readViews();
319 IndicesEntryList entries2 = this.dbClient.readTables();
320 if (entries == null) {
323 if (release == null) {
324 DatabaseVersion dbVersion;
326 dbVersion = this.dbClient.readActualVersion();
327 } catch (SQLException | ParseException e) {
328 LOG.error("unable to detect db version", e);
331 LOG.info("detected database version {}", dbVersion);
332 release = ReleaseGroup.CURRENT_RELEASE.getLatestCompatibleRelease(dbVersion, SdnrDbType.MARIADB);
333 if (release == null) {
334 LOG.warn("unable to autodetect release for this database version for release {}",
335 ReleaseGroup.CURRENT_RELEASE.name());
338 LOG.info("autodetect release {}", release);
340 ReleaseInformation ri = ReleaseInformation.getInstance(release);
342 if (entries.isEmpty()) {
343 LOG.info("no aliases to clear");
345 //check for every component of release if alias exists
346 for (ComponentName component : ri.getComponents()) {
347 String aliasToDelete = ri.getAlias(component, dbPrefix);
348 AliasesEntry entryToDelete = entries.findByAlias(aliasToDelete);
349 if (entryToDelete != null) {
351 LOG.info("deleting alias {} for index {}", entryToDelete.getAlias(), entryToDelete.getIndex());
352 response = this.dbClient.deleteView(entryToDelete.getAlias());
353 LOG.info(response ? "succeeded" : "failed");
354 } catch (SQLException e) {
355 LOG.error(e.getMessage());
359 //try to find malformed typed index with alias name
360 IndicesEntry entry2ToDelete = entries2.findByIndex(aliasToDelete);
361 if (entry2ToDelete != null) {
363 LOG.info(LOG_DELETING_INDEX, entry2ToDelete.getName());
364 response = this.dbClient.deleteTable(entry2ToDelete.getName());
365 LOG.info(response ? "succeeded" : "failed");
366 } catch (SQLException e) {
367 LOG.error(e.getMessage());
374 if (entries2 == null) {
377 if (entries2.isEmpty()) {
378 LOG.info("no indices to clear");
380 //check for every component of release if index exists
381 for (ComponentName component : ri.getComponents()) {
382 String indexToDelete = ri.getIndex(component, dbPrefix);
383 IndicesEntry entryToDelete = entries2.findByIndex(indexToDelete);
384 if (entryToDelete != null) {
386 LOG.info(LOG_DELETING_INDEX, entryToDelete.getName());
387 response = this.dbClient.deleteTable(entryToDelete.getName());
388 LOG.info(response ? "succeeded" : "failed");
389 } catch (SQLException e) {
390 LOG.error(e.getMessage());
404 public boolean clearCompleteDatabase(long timeoutms) {
406 this.dbClient.waitForYellowStatus(timeoutms);
408 //check aliases and indices
409 AliasesEntryList aliases = this.dbClient.readViews();
410 IndicesEntryList indices = this.dbClient.readTables();
411 if (aliases == null || indices == null) {
414 for (AliasesEntry alias : aliases) {
416 LOG.info("deleting alias {} for index {}", alias.getAlias(), alias.getIndex());
417 this.dbClient.deleteView(alias.getAlias());
418 } catch (SQLException e) {
419 LOG.error("problem deleting alias {}: {}", alias.getAlias(), e);
423 for (IndicesEntry index : indices) {
425 LOG.info(LOG_DELETING_INDEX, index.getName());
426 this.dbClient.deleteTable(index.getName());
427 } catch (SQLException e) {
428 LOG.error("problem deleting index {}: {}", index.getName(), e);