| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 com.cloud.upgrade; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.sql.Statement; |
| import java.sql.SQLException; |
| import java.sql.DriverManager; |
| import java.sql.Connection; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Properties; |
| |
| import org.springframework.context.support.ClassPathXmlApplicationContext; |
| |
| import com.cloud.utils.PropertiesUtil; |
| import com.cloud.utils.component.ComponentContext; |
| import com.cloud.utils.component.SystemIntegrityChecker; |
| import com.cloud.utils.db.ScriptRunner; |
| import com.cloud.utils.db.TransactionLegacy; |
| |
| // Creates the CloudStack Database by using the 4.0 schema and apply |
| // upgrade steps to it. |
| public class DatabaseCreator { |
| |
| protected static void printHelp(String cmd) { |
| System.out.println("\nDatabaseCreator creates the database schema by removing the \n" + "previous schema, creating the schema, and running \n" |
| + "through the database updaters."); |
| System.out.println("Usage: " + cmd + " [options] [db.properties file] [schema.sql files] [database upgrade class]\nOptions:" + |
| "\n --database=a,b comma separate databases to initialize, use the db name in db.properties defined as db.xyz.host, xyz should be passed" + |
| "\n --rootpassword=password, by default it will try with an empty password" + "\n --dry or -d, this would not run any process, just does a dry run" + |
| "\n --verbose or -v to print running sql commands, by default it won't print them" + "\n --help or -h for help"); |
| } |
| |
| private static boolean fileExists(String file) { |
| File f = new File(file); |
| if (!f.exists()) |
| System.out.println("========> WARNING: Provided file does not exist: " + file); |
| return f.exists(); |
| } |
| |
| private static void runScript(Connection conn, Reader reader, String filename, boolean verbosity) { |
| ScriptRunner runner = new ScriptRunner(conn, false, true, verbosity); |
| try { |
| runner.runScript(reader); |
| } catch (IOException e) { |
| System.err.println("Unable to read " + filename + ": " + e.getMessage()); |
| System.exit(1); |
| } catch (SQLException e) { |
| System.err.println("Unable to execute " + filename + ": " + e.getMessage()); |
| System.exit(1); |
| } |
| } |
| |
| private static void runQuery(String host, String port, String rootPassword, String query, boolean dryRun) { |
| System.out.println("============> Running query: " + query); |
| try (Connection conn = DriverManager.getConnection(String.format("jdbc:mysql://%s:%s/", host, port), "root", rootPassword); |
| Statement stmt = conn.createStatement();){ |
| if (!dryRun) |
| stmt.executeUpdate(query); |
| } catch (SQLException e) { |
| System.out.println("SQL exception in trying initDB: " + e); |
| System.exit(1); |
| } |
| } |
| |
| private static void initDB(String dbPropsFile, String rootPassword, String[] databases, boolean dryRun) { |
| Properties dbProperties = new Properties(); |
| try(FileInputStream f_stream = new FileInputStream(new File(dbPropsFile));) { |
| dbProperties.load(f_stream); |
| } catch (IOException e) { |
| System.out.println("IOError: unable to load/read db properties file: " + e); |
| System.exit(1); |
| } |
| |
| for (String database : databases) { |
| String host = dbProperties.getProperty(String.format("db.%s.host", database)); |
| String port = dbProperties.getProperty(String.format("db.%s.port", database)); |
| String username = dbProperties.getProperty(String.format("db.%s.username", database)); |
| String password = dbProperties.getProperty(String.format("db.%s.password", database)); |
| String dbName = dbProperties.getProperty(String.format("db.%s.name", database)); |
| System.out.println(String.format("========> Initializing database=%s with host=%s port=%s username=%s password=%s", dbName, host, port, username, password)); |
| |
| List<String> queries = new ArrayList<String>(); |
| queries.add(String.format("drop database if exists `%s`", dbName)); |
| queries.add(String.format("create database `%s`", dbName)); |
| queries.add(String.format("GRANT ALL ON %s.* to '%s'@`localhost` identified by '%s'", dbName, username, password)); |
| queries.add(String.format("GRANT ALL ON %s.* to '%s'@`%%` identified by '%s'", dbName, username, password)); |
| |
| for (String query : queries) { |
| runQuery(host, port, rootPassword, query, dryRun); |
| } |
| } |
| } |
| |
| public static void main(String[] args) { |
| |
| ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] {"/com/cloud/upgrade/databaseCreatorContext.xml"}); |
| appContext.getBean(ComponentContext.class); |
| |
| String dbPropsFile = ""; |
| List<String> sqlFiles = new ArrayList<String>(); |
| List<String> upgradeClasses = new ArrayList<String>(); |
| String[] databases = new String[] {}; |
| String rootPassword = ""; |
| boolean verbosity = false; |
| boolean dryRun = false; |
| |
| // Process opts |
| for (String arg : args) { |
| if (arg.equals("--help") || arg.equals("-h")) { |
| printHelp("DatabaseCreator"); |
| System.exit(0); |
| } else if (arg.equals("--verbose") || arg.equals("-v")) { |
| verbosity = true; |
| } else if (arg.equals("--dry") || arg.equals("-d")) { |
| dryRun = true; |
| } else if (arg.startsWith("--rootpassword=")) { |
| rootPassword = arg.substring(arg.lastIndexOf("=") + 1, arg.length()); |
| } else if (arg.startsWith("--database=")) { |
| databases = arg.substring(arg.lastIndexOf("=") + 1, arg.length()).split(","); |
| } else if (arg.endsWith(".sql")) { |
| sqlFiles.add(arg); |
| } else if (arg.endsWith(".sql.override")) { |
| if (fileExists(arg)) { |
| int index = arg.lastIndexOf(".override"); |
| String fileToOverride = arg.substring(0, index); |
| sqlFiles.remove(fileToOverride); |
| sqlFiles.add(arg); |
| } |
| } else if (arg.endsWith(".properties")) { |
| if (!dbPropsFile.endsWith("properties.override") && fileExists(arg)) |
| dbPropsFile = arg; |
| } else if (arg.endsWith("properties.override")) { |
| if (fileExists(arg)) |
| dbPropsFile = arg; |
| } else { |
| upgradeClasses.add(arg); |
| } |
| } |
| |
| if ((dbPropsFile.isEmpty()) || (sqlFiles.size() == 0) && upgradeClasses.size() == 0) { |
| printHelp("DatabaseCreator"); |
| System.exit(1); |
| } |
| |
| try { |
| TransactionLegacy.initDataSource(dbPropsFile); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| System.exit(1); |
| } |
| initDB(dbPropsFile, rootPassword, databases, dryRun); |
| |
| // Process sql files |
| for (String sqlFile : sqlFiles) { |
| File sqlScript = PropertiesUtil.findConfigFile(sqlFile); |
| if (sqlScript == null) { |
| System.err.println("Unable to find " + sqlFile); |
| printHelp("DatabaseCreator"); |
| System.exit(1); |
| } |
| |
| System.out.println("========> Processing SQL file at " + sqlScript.getAbsolutePath()); |
| |
| try(Connection conn = TransactionLegacy.getStandaloneConnection(); |
| FileReader reader = new FileReader(sqlScript); |
| ) { |
| if (!dryRun) |
| runScript(conn, reader, sqlFile, verbosity); |
| }catch (SQLException e) |
| { |
| System.err.println("Sql Exception:" + e.getMessage()); |
| System.exit(1); |
| } |
| catch (IOException e) |
| { |
| System.err.println("File IO Exception : " + e.getMessage()); |
| System.exit(1); |
| } |
| |
| } |
| |
| TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB); |
| try { |
| // Process db upgrade classes |
| for (String upgradeClass : upgradeClasses) { |
| System.out.println("========> Processing upgrade: " + upgradeClass); |
| Class<?> clazz = null; |
| try { |
| clazz = Class.forName(upgradeClass); |
| if (!SystemIntegrityChecker.class.isAssignableFrom(clazz)) { |
| System.err.println("The class must be of SystemIntegrityChecker: " + clazz.getName()); |
| System.exit(1); |
| } |
| SystemIntegrityChecker checker = (SystemIntegrityChecker)clazz.newInstance(); |
| checker.check(); |
| } catch (ClassNotFoundException e) { |
| System.err.println("Unable to find " + upgradeClass + ": " + e.getMessage()); |
| System.exit(1); |
| } catch (InstantiationException e) { |
| System.err.println("Unable to instantiate " + upgradeClass + ": " + e.getMessage()); |
| System.exit(1); |
| } catch (IllegalAccessException e) { |
| System.err.println("Unable to access " + upgradeClass + ": " + e.getMessage()); |
| System.exit(1); |
| } |
| |
| } |
| } finally { |
| txn.close(); |
| } |
| System.exit(0); |
| } |
| } |