Permalink
Browse files

Added MySQL master-slave (1st iteration-No Failover)

  • Loading branch information...
1 parent 9d563b4 commit 969b16fffd951b519100dfeb655f2a8dc0af60e3 @tamirko tamirko committed Sep 24, 2012
View
2 apps/lamp/mysql/mysql-service.properties
@@ -25,7 +25,7 @@ dbPassW="lampdb"
currDBZip="sample.zip"
currImportSql="sample.sql"
-importedFileUrl="http://dl.dropbox.com/u/58809323/${currDBZip}"
+importedFileUrl="http://repository.cloudifysource.org/org/cloudifysource/examples/lamp/1.0.0/${currDBZip}"
/* Use the following format - leave an empty string (startDetectionQuery="") for using the default startDetection ( by port ) :
View
9 apps/masterslave/masterslave-application.groovy
@@ -0,0 +1,9 @@
+application {
+ name "masterslave"
+
+ service {
+ name = "mysql"
+ }
+}
+
+
View
4 apps/masterslave/mysql/mysql-service.groovy
@@ -0,0 +1,4 @@
+service {
+ extend "../../../services/mysql"
+ numInstances 3
+}
View
228 apps/masterslave/mysql/mysql-service.properties
@@ -0,0 +1,228 @@
+serviceName="mysqlmaster"
+jdbcPort=3306
+
+win64 {
+ mysqlHome="mysql-5.5.24-winx64"
+ mysqlD="mysqld.exe"
+ mysqlProgram="mysql.exe"
+ mysqladmin="mysqladmin.exe"
+ mysqldump="mysqldump.exe"
+ zipName="${mysqlHome}.zip"
+ /* http://downloads.skysql.com/archive/index/p/mysql/v/5.5.24 */
+ zipURL="http://downloads.skysql.com/archives/mysql-5.5/${zipName}"
+}
+
+linux {
+ mysqlD="mysqld"
+ mysqlProgram="mysql"
+ mysqladmin="mysqladmin"
+ mysqldump="mysqldump"
+}
+
+
+dbName="lampdb"
+dbUser="lampdb"
+dbPassW="lampdb"
+
+currDBZip="sample.zip"
+currImportSql="sample.sql"
+importedFileUrl="http://repository.cloudifysource.org/org/cloudifysource/examples/lamp/1.0.0/${currDBZip}"
+
+/* Use the following format - leave an empty string (startDetectionQuery="") for using the default startDetection ( by port ) :
+ startDetectionQuery="select count(XXX) as cc from table_name"
+*/
+startDetectionQuery="select count(name) as cc from persons"
+
+
+/*
+ myCnfReplacements enables users to replace properties in the my.cnf file
+ Do NOT set the server-id , it will be set by this recipe
+*/
+
+myCnfReplacements = [
+ [
+ "section" : "mysqld",
+ "variable" : "bind-address" ,
+ "newValue" : "0.0.0.0"
+ ],
+
+ [
+ "section" : "mysqld",
+ "variable" : "log-bin" ,
+ "newValue" : "mysql-bin"
+ ],
+
+ [
+ "section" : "mysqld",
+ "variable" : "binlog_format" ,
+ "newValue" : "MIXED"
+ ],
+
+ [
+ "section" : "mysqld",
+ "variable" : "max_binlog_size" ,
+ "newValue" : "1456200"
+ ],
+
+ [
+ "section" : "mysqld",
+ "variable" : "expire_logs_days" ,
+ "newValue" : "10"
+ ]
+]
+
+/* Set masterSlaveMode to true, if you want the instances to run as master or slave.
+ If masterSlaveMode is set to false, then all the service instances will run in standalone mode. */
+masterSlaveMode=true
+
+/*
+ actionType can be one of the four following: mysqladmin,mysql,mysqldump or import
+ Examples :
+
+ // In this case, dbName is a property which is defined in this properties file
+ // All the occurrences of MYSQLHOST in actionQuery, will be replaced with the private IP address on which this service instance resides
+ [
+ "actionType" : "mysqladmin",
+ "actionQuery" : "create" ,
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Creating db - Name : ${dbName} ... "
+ ] ,
+
+
+ // In this case, dbUser and dbPassW are properties which are defined in this properties file
+ // All the occurrences of MYSQLHOST in actionQuery, will be replaced with the private IP address on which this service instance resides
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"CREATE USER '${dbUser}'@'localhost' IDENTIFIED BY '${dbPassW}';\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Creating db user ${dbUser} at localhost, passw ${dbPassW} in ${dbName} db... "
+ ],
+
+ // In this case:
+ // dbName,currDBZip,currImportSql are properties which are defined in this properties file
+ // currDBZip is the local name of the zip file ( after download )
+ // currImportSql is the name of the sql file which is stored in currDBZip.
+ // All the occurrences of REPLACE_WITH_DB_NAME in currImportSql, will be replaced with ${dbName}
+ [
+ "actionType" : "import",
+ "importedZip" : "${currDBZip}",
+ "importedFile" : "${currImportSql}",
+ "importedFileUrl" : "http://dropbox/1/222/mysql.zip",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Importing to ${dbName} ..."
+ ]
+
+ // In this case:
+ // dbName is a property which is defined in this properties file.
+ // if actionDbName is an empty string, then --all-databases will be used
+ // actionArgs contain the flags that you want to use with this mysqldump command
+ // Do NOT database flags, because they will be set according to the actionDbName.
+ // So do NOT use the following : --all-databases,-A,--databases, -B
+ // Do NOT -u flag flags, because it will be set according to the actionUser
+ [
+ "actionType" : "mysqldump",
+ "actionArgs" : "--add-drop-database -c --lock-all-tables -F",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "dumpPrefix" : "myDumpFile_",
+ "debugMsg" : "Invoking mysqldump ..."
+ ]
+
+*/
+postStartActions = [
+ [
+ "actionType" : "mysqladmin",
+ "actionQuery" : "create" ,
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Creating db - Name : ${dbName} ... "
+ ],
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"CREATE USER '${dbUser}'@'localhost' IDENTIFIED BY '${dbPassW}';\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Creating db user ${dbUser} at localhost, passw ${dbPassW} in ${dbName} db... "
+ ],
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"CREATE USER '${dbUser}'@'MYSQLHOST' IDENTIFIED BY '${dbPassW}';\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Creating db user ${dbUser} at MYSQLHOST, passw ${dbPassW} in ${dbName} db... "
+ ],
+
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"CREATE USER '${dbUser}'@'%' IDENTIFIED BY '${dbPassW}';\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Creating db user ${dbUser} at all hosts, passw ${dbPassW} in ${dbName} db... "
+ ],
+
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"grant usage on *.* to ${dbUser}@localhost identified by '${dbPassW}';\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Granting usage to user ${dbUser} at localhost, passw ${dbPassW} in ${dbName} db..."
+ ],
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"grant usage on *.* to ${dbUser}@MYSQLHOST identified by '${dbPassW}';\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Granting usage to user ${dbUser} at MYSQLHOST, passw ${dbPassW} in ${dbName} db..."
+ ],
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"grant usage on *.* to ${dbUser}@'%' identified by '${dbPassW}';\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Granting usage to user ${dbUser} at all hosts, passw ${dbPassW} in ${dbName} db..."
+ ],
+
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"grant all privileges on *.* to ${dbUser}@'localhost' with grant option;\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Granting all privileges to user ${dbUser} in ${dbName} db at localhost... "
+ ],
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"grant all privileges on *.* to ${dbUser}@'MYSQLHOST' with grant option;\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Granting all privileges to user ${dbUser} in ${dbName} db at MYSQLHOST... "
+ ],
+
+ [
+ "actionType" : "mysql",
+ "actionQuery" : "\"grant all privileges on *.* to ${dbUser}@'%' with grant option;\"",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Granting all privileges to user ${dbUser} in ${dbName} db at all hosts ... "
+ ],
+
+ [
+ "actionType" : "import",
+ "importedZip" : "${currDBZip}",
+ "importedFile" : "${currImportSql}",
+ "importedFileUrl" : "${importedFileUrl}",
+ "actionUser" : "root",
+ "actionDbName" : "${dbName}",
+ "debugMsg" : "Importing to ${dbName} ..."
+ ]
+]
View
BIN apps/masterslave/mysql/usmlib/mysql-admin-1.0-SNAPSHOT.jar
Binary file not shown.
View
BIN apps/masterslave/mysql/usmlib/mysql-connector-java-5.1.17-bin.jar
Binary file not shown.
View
79 services/mysql/README.md
@@ -38,7 +38,11 @@ Synopsis
This folder contains a service recipe for MySQL.
-Its default port is 3306, but it can be modified in the mysql-service.properties.
+This recipe enables users to install MySQL in two modes: standalone and master-slave.
+In a master-slave mode, the first instance of the service is the master and all the other instances are slaves.
+In order to work in a master-slave mode, you need to set the masterSlaveMode property to true in mysql-service.properties file.
+
+The default port is 3306, but it can be modified in the mysql-service.properties file.
You can inherit and extend this recipe very easily, just by changing the mysql-service.properties file, without changing even one line of code in the recipe.
@@ -127,14 +131,47 @@ Examples :
</code></pre>
+3: <strong>my.cnf variables Replacement</strong>
+
+In the properties file you can insert an array of my.cnf variables and their corresponding values (as many commands as you want).
+Do NOT set the server-id variable, as it will be set by this recipe.
+These variables will be replaced during the install lifecycle event.
+
+Examples :
+
+<pre><code>
+ /* In this case, the value of the log-bin,
+ will be set to mysql-bin in the mysqld section of my.cnf.
+ */
+ [
+ "section" : "mysqld",
+ "variable" : "log-bin" ,
+ "newValue" : "mysql-bin"
+ ],
+
+ /* In this case, the value of the binlog_format ,
+ will be set to MIXED (ROW and STATEMENT) in the mysqld section of my.cnf.
+ */
+
+ [
+ "section" : "mysqld",
+ "variable" : "binlog_format" ,
+ "newValue" : "MIXED"
+ ]
+
+</code></pre>
+
+
+
## Custom Commands
**mysqldump**:
This custom command enables users to create a database snapshot (mysqldump).
Usage : <strong>invoke mysql mysqldump actionUser dumpPrefix [dbName]</strong>
Example: <strong>invoke mysql mysqldump root myPrefix_ myDbName</strong>
-
+
+
**query**:
This custom command enables users to invoke an SQL statement.
@@ -151,3 +188,41 @@ Examples:
then you need to run the following custom command :
<strong>invoke mysql query root tamirDB \\\"INSERT INTO users VALUES \\\\(17,\\\'Dan\\\',\\\'hisPassword\\\',\\\'hisemail@his.com\\\',0\\\\)\\\"</strong>
+
+**import**:
+
+This custom command enables users to import a zipped file to a database
+Usage : <strong>invoke import actionUser dbName zipFileURL</strong>
+Example: <strong>invoke import root myDbName http://www.mysite.com/myFile.zip</strong>
+
+
+**addSlave**:
+
+This custom command enables users to add a slave to the master.
+It should be invoked only on a master instance (by a remote slave)
+and only if masterSlaveMode is set to true on both the slave and master.
+As a result, the following will be invoked :
+mysql -u root -D dbName -e "GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO slaveUser@'slaveHostIP' IDENTIFIED BY 'slavePassword';"
+
+Usage : <strong>invoke mysqlmaster addSlave actionUser dbName slaveUser slavePassword slaveHostIP</strong>
+
+
+**showMasterStatus**:
+
+This custom command enables users to show the master's status.
+It should be invoked only on a master instance (either by the master or by a remote slave)
+and only if masterSlaveMode is set to true.
+As a result, the following will be invoked :
+mysql -u root -D dbName -e "show master status;"
+and then the mysql-bin will be stored in context.attributes.thisApplication["masterBinLogFile"]
+and the master's log's position will be stored in context.attributes.thisApplication["masterBinLogPos"]
+
+Usage : <strong>invoke mysqlmaster showMasterStatus actionUser dbName</strong>
+
+
+## Known Issues
+
+ * Monitoring is not implemented yet. It will be available in the future.
+ * Failover in the master-slave mode is NOT implemented yet. It will be available in the future.
+
+
View
58 services/mysql/install.sh
@@ -1,6 +1,17 @@
#!/bin/bash
# args:
+# $1 A command separated list of my.cnf section names
+# $2 A command separated list of my.cnf variable names
+# $3 A command separated list of my.cnf values for the above variable names
+#
+
+sectionNames=$1
+variableNames=$2
+newValues=$3
+
+
+# args:
# $1 the error code of the last command (should be explicitly passed)
# $2 the message to print in case of an error
#
@@ -52,24 +63,41 @@ sudo yum reinstall -y -q mysql-libs || error_exit $? "Failed on: sudo yum instal
echo "Killing old mysql process if exists b4 ending the installation..."
killMySqlProcess
+sectionNamesLen=`expr length "$sectionNames"`
+if [ $sectionNamesLen -gt 0 ] ; then
-myCnfPath=`sudo find / -name "my.cnf"`
-if [ -f "${myCnfPath}" ] ; then
- allZeroes="0.0.0.0"
- bindcount=`grep -c "bind-address" $myCnfPath`
- if [ $bindcount -eq 0 ] ; then
- bindStr="bind-address=${allZeroes}"
- mysqldStr="\[mysqld\]"
- jointStr="${mysqldStr}\n${bindStr}"
- echo "Adding ${bindStr} $myCnfPath ... "
- sudo sed -i -e "s/$mysqldStr/$jointStr/g" $myCnfPath
- else
- orig127="127.0.0.1"
- echo "Replacing $orig127 with $allZeroes in $myCnfPath ... "
- sudo sed -i -e "s/$orig127/$allZeroes/g" $myCnfPath
+ myCnfPath=`sudo find / -name "my.cnf"`
+ if [ -f "${myCnfPath}" ] ; then
+
+ sectionNames=$1
+ variableNames=$2
+ newValues=$3
+
+ IFS=, read -a sectionNamesArr <<< "$sectionNames"
+ IFS=, read -a variableNamesArr <<< "$variableNames"
+ IFS=, read -a newValuesArr <<< "$newValues"
+ echo "IFS is ${IFS}"
+ echo "${sectionNamesArr[@]}"
+ echo "${variableNamesArr[@]}"
+ echo "${newValuesArr[@]}"
+
+ variableCounter=${#variableNamesArr[@]}
+
+ for (( i=0; i<${variableCounter}; i++ ));
+ do
+ currSection="\[${sectionNamesArr[$i]}\]"
+ currVariable="${variableNamesArr[$i]}"
+ currNewValue="${newValuesArr[$i]}"
+ currNewLine="${currVariable}=${currNewValue}"
+ echo "Commenting $currVariable in $myCnfPath ... "
+ sudo sed -i -e "s/^$currVariable/#$currVariable/g" $myCnfPath
+
+ jointStr="${currSection}\n${currNewLine}"
+ echo "Setting ${currNewLine} in the ${currSection} section of $myCnfPath ... "
+ sudo sed -i -e "s/$currSection/$jointStr/g" $myCnfPath
+ done
fi
fi
-
echo "End of $0"
View
65 services/mysql/installOnUbuntu.sh
@@ -1,6 +1,16 @@
#!/bin/bash -x
# args:
+# $1 A command separated list of my.cnf section names
+# $2 A command separated list of my.cnf variable names
+# $3 A command separated list of my.cnf values for the above variable names
+#
+
+sectionNames=$1
+variableNames=$2
+newValues=$3
+
+# args:
# $1 the error code of the last command (should be explicitly passed)
# $2 the message to print in case of an error
#
@@ -47,26 +57,39 @@ sudo DEBIAN_FRONTEND='noninteractive' apt-get -o Dpkg::Options::='--force-confne
echo "Killing old mysql process if exists b4 ending the installation..."
killMySqlProcess
-myCnfPath=`sudo find / -name "my.cnf"`
-if [ -f "${myCnfPath}" ] ; then
- allZeroes="0.0.0.0"
- bindcount=`grep -c "bind-address" $myCnfPath`
- if [ $bindcount -eq 0 ] ; then
- bindStr="bind-address=${allZeroes}"
- mysqldStr="\[mysqld\]"
- jointStr="${mysqldStr}\n${bindStr}"
- echo "Adding ${bindStr} $myCnfPath ... "
- sudo sed -i -e "s/$mysqldStr/$jointStr/g" $myCnfPath
- else
- orig127="127.0.0.1"
- echo "Replacing $orig127 with $allZeroes in $myCnfPath ... "
- sudo sed -i -e "s/$orig127/$allZeroes/g" $myCnfPath
+sectionNamesLen=`expr length "$sectionNames"`
+if [ $sectionNamesLen -gt 0 ] ; then
+
+ myCnfPath=`sudo find / -name "my.cnf"`
+ if [ -f "${myCnfPath}" ] ; then
+
+ sectionNames=$1
+ variableNames=$2
+ newValues=$3
+
+ IFS=, read -a sectionNamesArr <<< "$sectionNames"
+ IFS=, read -a variableNamesArr <<< "$variableNames"
+ IFS=, read -a newValuesArr <<< "$newValues"
+ echo "IFS is ${IFS}"
+ echo "${sectionNamesArr[@]}"
+ echo "${variableNamesArr[@]}"
+ echo "${newValuesArr[@]}"
+
+ variableCounter=${#variableNamesArr[@]}
+
+ for (( i=0; i<${variableCounter}; i++ ));
+ do
+ currSection="\[${sectionNamesArr[$i]}\]"
+ currVariable="${variableNamesArr[$i]}"
+ currNewValue="${newValuesArr[$i]}"
+ currNewLine="${currVariable}=${currNewValue}"
+ echo "Commenting $currVariable in $myCnfPath ... "
+ sudo sed -i -e "s/^$currVariable/#$currVariable/g" $myCnfPath
+
+ jointStr="${currSection}\n${currNewLine}"
+ echo "Setting ${currNewLine} in the ${currSection} section of $myCnfPath ... "
+ sudo sed -i -e "s/$currSection/$jointStr/g" $myCnfPath
+ done
fi
fi
-
-echo "End of $0"
-
-
-
-#sudo service mysql stop
-#sudo service mysql start
+echo "End of $0"
View
41 services/mysql/mysql-service.groovy
@@ -22,6 +22,10 @@ service {
icon "mysql.png"
type "DATABASE"
+ elastic true
+ numInstances 1
+ minAllowedInstances 1
+ maxAllowedInstances 3
compute {
template "SMALL_LINUX"
@@ -73,7 +77,42 @@ service {
Usage : invoke mysql query actionUser dbName query
Example: invoke mysql query root myDbName "update users set city=\"NY\" where uid=15"
*/
- "query" : "mysql_query.groovy"
+ "query" : "mysql_query.groovy" ,
+
+ /*
+ This custom command enables users to add a slave to the master.
+ It should be invoked only on a master instance (by a remote slave)
+ and only if masterSlaveMode is set to true on both the slave and master.
+ As a result, the following will be invoked :
+ mysql -u root -D dbName -e
+ "GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO slaveUser@'slaveHostIP' IDENTIFIED BY 'slavePassword';"
+
+ Usage : invoke mysqlmaster addSlave actionUser dbName slaveUser slavePassword slaveHostIP
+
+ */
+ "addSlave": "mysql_addSlave.groovy" ,
+
+ /*
+ This custom command enables users to show the master's status.
+ It should be invoked only on a master instance (either by the master or by a remote slave)
+ and only if masterSlaveMode is set to true.
+ As a result, the following will be invoked :
+ mysql -u root -D dbName -e "show master status;"
+ and the mysql-bin will be stored in context.attributes.thisApplication["masterBinLogFile"]
+ and the master's log's position will be stored in context.attributes.thisApplication["masterBinLogPos"]
+
+ Usage : invoke mysqlmaster showMasterStatus actionUser dbName
+
+ */
+ "showMasterStatus": "mysql_showMasterStatus.groovy" ,
+
+ /*
+ This custom command enables users to import a zipped file to a database
+ Usage : invoke import actionUser dbName zipFileURL
+ Example: invoke import root myDbName http://www.mysite.com/myFile.zip
+ */
+
+ "import" : "mysql_import.groovy"
])
View
18 services/mysql/mysql-service.properties
@@ -25,6 +25,24 @@ dbUser="tamir"
dbPassW="1234"
+/*
+ myCnfReplacements enables user to replace properties in the my.cnf file.
+ You can use as many propeties as you want.
+*/
+
+myCnfReplacements = [
+ [
+ "section" : "mysqld",
+ "variable" : "bind-address" ,
+ "newValue" : "0.0.0.0"
+ ]
+]
+
+/* Set masterSlaveMode to true, if you want the instances to run as master or slave.
+ If masterSlaveMode is set to false, then all the service instances will run in standalone mode. */
+masterSlaveMode=false
+
+
/* Use the following format - leave an empty string (startDetectionQuery="") for using the default startDetection ( by port ) :
startDetectionQuery="select count(XXX) as cc from table_name"
*/
View
92 services/mysql/mysql_addSlave.groovy
@@ -0,0 +1,92 @@
+/*******************************************************************************
+* Copyright (c) 2011 GigaSpaces Technologies Ltd. All rights reserved
+*
+* 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.
+*******************************************************************************/
+import org.hyperic.sigar.OperatingSystem
+import org.cloudifysource.dsl.utils.ServiceUtils;
+import org.cloudifysource.dsl.context.ServiceContextFactory
+import static mysql_runner.*
+
+
+/*
+ This file enables users to add a slave to the master.
+ It should be invoked only on a master instance (by a remote slave) and only if masterSlaveMode is set to true on both the slave and master.
+ As a result, the following will be invoked :
+ mysql -u root -D dbName -e "GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO slaveUser@'slaveHostIP' IDENTIFIED BY 'slavePassword';"
+
+ Usage : invoke mysqlmaster addSlave actionUser dbName slaveUser slavePassword slaveHostIP
+*/
+
+config=new ConfigSlurper().parse(new File('mysql-service.properties').toURL())
+osConfig=ServiceUtils.isWindows() ? config.win64 : config.linux
+context = ServiceContextFactory.getServiceContext()
+
+
+
+if ( !config.masterSlaveMode ) {
+ println "mysql_addSlave.groovy: masterSlaveMode is disabled. I cannot invoke addSlave"
+ System.exit(-1)
+}
+
+def isMaster = context.attributes.thisInstance["isMaster"]
+
+if ( !isMaster ) {
+ println "mysql_addSlave.groovy: I am not a master. I cannot invoke addSlave"
+ System.exit(-1)
+}
+
+binFolder=context.attributes.thisInstance["binFolder"]
+println "mysql_addSlave.groovy: binFolder is ${binFolder} "
+
+def currActionQuery
+def currOsName
+
+def os = OperatingSystem.getInstance()
+def currVendor=os.getVendor()
+switch (currVendor) {
+ case ["Ubuntu", "Debian", "Mint"]:
+ currOsName="unix"
+ break
+ case ["Red Hat", "CentOS", "Fedora", "Amazon",""]:
+ currOsName="unix"
+ break
+ case ~/.*(?i)(Microsoft|Windows).*/:
+ currOsName="windows"
+ break
+ default: throw new Exception("Support for ${currVendor} is not implemented")
+}
+
+
+if (args.length < 5) {
+ println "mysql_addSlave.groovy: addSlave error: Missing parameters\nUsage: invoke mysqlmaster addSlave actionUser dbName slaveUser slavePassword slaveHostIP"
+ System.exit(-1)
+}
+
+def currActionUser = args[0]
+def currActionDbName = args[1]
+def slaveUser = args[2]
+def slavePassword = args[3]
+def slaveHostIP = args[4]
+
+
+def grantStr = "GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO ${slaveUser}@'${slaveHostIP}' IDENTIFIED BY '${slavePassword}';"
+def currQuery = "\"" + grantStr + "\""
+def currDebugMsg = "Invoking query: ${currQuery}"
+
+println "mysql_addSlave.groovy: b4 invoking ${currQuery} ... "
+runMysqlQuery(binFolder,osConfig.mysqlProgram,currOsName,currQuery as String,currActionDbName as String,currActionUser as String,currDebugMsg as String,"addSlaveOutput",true)
+
+println "mysql_addSlave.groovy: End"
+
+
View
90 services/mysql/mysql_import.groovy
@@ -0,0 +1,90 @@
+/*******************************************************************************
+* Copyright (c) 2011 GigaSpaces Technologies Ltd. All rights reserved
+*
+* 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.
+*******************************************************************************/
+import org.hyperic.sigar.OperatingSystem
+import org.cloudifysource.dsl.utils.ServiceUtils;
+import org.cloudifysource.dsl.context.ServiceContextFactory
+import static mysql_runner.*
+
+
+/*
+ This custom command enables users to import a zipped file to a database
+ Usage : invoke import actionUser dbName zipFileURL
+ Example: invoke import root myDbName http://www.mysite.com/myFile.zip
+*/
+
+config=new ConfigSlurper().parse(new File('mysql-service.properties').toURL())
+osConfig=ServiceUtils.isWindows() ? config.win64 : config.linux
+context = ServiceContextFactory.getServiceContext()
+mysqlHost=context.attributes.thisInstance["dbHost"]
+binFolder=context.attributes.thisInstance["binFolder"]
+println "mysql_import.groovy: mysqlHost is ${mysqlHost} "
+
+def currActionQuery
+def currOsName
+
+def os = OperatingSystem.getInstance()
+def currVendor=os.getVendor()
+switch (currVendor) {
+ case ["Ubuntu", "Debian", "Mint"]:
+ currOsName="unix"
+ break
+ case ["Red Hat", "CentOS", "Fedora", "Amazon",""]:
+ currOsName="unix"
+ break
+ case ~/.*(?i)(Microsoft|Windows).*/:
+ currOsName="windows"
+ break
+ default: throw new Exception("Support for ${currVendor} is not implemented")
+}
+
+
+if (args.length < 3) {
+ println "mysql_import.groovy: import error: Missing parameters\nUsage: invoke import actionUser dbName zipFileURL"
+ System.exit(-1)
+}
+
+
+def currActionUser = args[0]
+def currActionDbName = args[1]
+def importedFileUrl = args[2]
+
+def currDebugMsg = "Invoking import: ${importedFileUrl}"
+
+def builder = new AntBuilder()
+
+def localZip="${context.serviceDirectory}/localZip.zip"
+
+builder.sequential {
+ echo(message:"mysql_import.groovy: import: Getting ${importedFileUrl} to ${localZip} ...")
+ get(src:"${importedFileUrl}", dest:"${localZip}", skipexisting:false)
+ echo(message:"mysql_import.groovy: import: Unzipping ${localZip} to ${context.serviceDirectory} ...")
+ unzip(src:"${localZip}", dest:"${context.serviceDirectory}", overwrite:true)
+}
+
+def fullPathToImport
+
+def currZipFile = new java.util.zip.ZipFile(new File("${localZip}"))
+currZipFile.entries().each { entry ->
+ fullPathToImport = "${context.serviceDirectory}/${entry}"
+ println "mysql_import.groovy: import: fullPathToImport is ${fullPathToImport}"
+}
+
+
+importMysqlDB(binFolder,osConfig.mysqlProgram,currOsName,fullPathToImport as String,currActionDbName,currActionUser,currDebugMsg as String,"importOutput",true)
+
+println "mysql_import.groovy: End"
+
+
View
119 services/mysql/mysql_install.groovy
@@ -18,7 +18,7 @@ import org.cloudifysource.dsl.utils.ServiceUtils;
import org.hyperic.sigar.OperatingSystem
-def installLinuxMysql(context,builder,currVendor,installScript) {
+def installLinuxMysql(context,builder,currVendor,installScript,myCnfObject) {
if ( context.isLocalCloud() ) {
if ( context.attributes.thisApplication["installing"] == null || context.attributes.thisApplication["installing"] == false ) {
@@ -32,12 +32,21 @@ def installLinuxMysql(context,builder,currVendor,installScript) {
}
}
+ def sectionNames = myCnfObject["sectionNames"]
+ def variableNames = myCnfObject["variableNames"]
+ def newValues = myCnfObject["newValues"]
+
+
builder.sequential {
echo(message:"mysql_install.groovy: Chmodding +x ${context.serviceDirectory} ...")
chmod(dir:"${context.serviceDirectory}", perm:"+x", includes:"*.sh")
echo(message:"mysql_install.groovy: Running ${context.serviceDirectory}/${installScript} os is ${currVendor}...")
- exec(executable: "${context.serviceDirectory}/${installScript}",failonerror: "true")
+ exec(executable: "${context.serviceDirectory}/${installScript}",failonerror: "true") {
+ arg(value:"${sectionNames}")
+ arg(value:"${variableNames}")
+ arg(value:"${newValues}")
+ }
}
if ( context.isLocalCloud() ) {
@@ -46,20 +55,115 @@ def installLinuxMysql(context,builder,currVendor,installScript) {
}
}
-def installWindowsMysql(config,osConfig,unzipDir,zipFullPath,builder) {
+def installWindowsMysql(config,osConfig,unzipDir,zipFullPath,builder,myCnfObject) {
builder.sequential {
mkdir(dir:"${unzipDir}")
- echo(message:"mysql_install.groovy get ${osConfig.zipURL} ... ")
+ echo(message: "mysql_install.groovy get ${osConfig.zipURL} ... ")
get(src:"${osConfig.zipURL}", dest:"${zipFullPath}", skipexisting:true)
echo(message:"mysql_install.groovy: Unzipping ${zipFullPath} to ${context.serviceDirectory}...")
unzip(src:"${zipFullPath}", dest:"${context.serviceDirectory}", overwrite:true)
}
}
+def getCnfObject(config,context,isMaster,isSlave) {
+
+ def sectionNames = ""
+ def variableNames = ""
+ def newValues = ""
+
+ def varaiblesCounter = 1
+
+ def newMyCnfObject = [
+ "sectionNames" : "" ,
+ "variableNames" : "",
+ "newValues" : ""
+ ]
+
+
+ if ( config.masterSlaveMode ) {
+ println "mysql_install.groovy: getCnfObject: masterSlaveMode"
+
+ if ( isMaster ) {
+ println "mysql_install.groovy: getCnfObject: variables set #${varaiblesCounter} (server-id)"
+ sectionNames +="mysqld,"
+ variableNames +="server-id,"
+ newValues +="1,"
+ ++varaiblesCounter
+ }
+ else if ( isSlave ) {
+ // id 1 is for the master. So the slaves instances will start from id #2
+ println "mysql_install.groovy: getCnfObject: variables set #${varaiblesCounter} (server-id)"
+ def slaveServerID = context.getInstanceId()+1
+ sectionNames +="mysqld,"
+ variableNames +="server-id,"
+ newValues +="${slaveServerID},"
+ ++varaiblesCounter
+ }
+ }
+
+ def myCnfReplacements
+ if ( config.myCnfReplacements ) {
+ myCnfReplacements = config.myCnfReplacements
+ if ( myCnfReplacements.size > 0 ) {
+ println "mysql_install.groovy: getCnfObject: There are " +myCnfReplacements.size + " myCnfReplacements "
+ for ( currActionObj in myCnfReplacements ) {
+ def currSection = currActionObj["section"]
+ def currVariable = currActionObj["variable"]
+ def currNewValue = currActionObj["newValue"]
+ sectionNames +=currSection+","
+ variableNames +=currVariable+","
+ newValues +=currNewValue+","
+ println "mysql_install.groovy: getCnfObject: variables set #${varaiblesCounter} (${currVariable})"
+ ++varaiblesCounter
+ }
+ }
+ }
+
+
+ if ( sectionNames.length() > 0 && sectionNames.endsWith(",")) {
+ newMyCnfObject.put("sectionNames",sectionNames[0..-2])
+ newMyCnfObject.put("variableNames",variableNames[0..-2])
+ newMyCnfObject.put("newValues",newValues[0..-2])
+ println "mysql_install.groovy: getCnfObject: mycnf sectionNames is "+newMyCnfObject["sectionNames"]
+ println "mysql_install.groovy: getCnfObject: mycnf variableNames is "+newMyCnfObject["variableNames"]
+ println "mysql_install.groovy: getCnfObject: mycnf newValues is "+newMyCnfObject["newValues"]
+ }
+
+
+ return newMyCnfObject
+}
+
config=new ConfigSlurper().parse(new File('mysql-service.properties').toURL())
osConfig=ServiceUtils.isWindows() ? config.win64 : config.linux
context = ServiceContextFactory.getServiceContext()
+def myInstanceID=context.getInstanceId()
+
+def isMaster=false
+def isSlave=false
+
+if ( config.masterSlaveMode ) {
+ println "mysql_install.groovy: masterSlaveMode"
+ if ( myInstanceID == 1 ) {
+ println "mysql_install.groovy: I am a master b4 setting isMaster to true and isSlave to false..."
+ isMaster = true
+ context.attributes.thisService["masterIsReady"]=false
+ context.attributes.thisService["masterID"]=myInstanceID
+ isSlave = false
+ }
+ else {
+ println "mysql_install.groovy: I am a slave(instance id ${myInstanceID}) b4 setting isSlave to true and isMaster to false..."
+ isMaster = false
+ isSlave = true
+ }
+
+ context.attributes.thisInstance["isSlave"]=isSlave
+ context.attributes.thisInstance["isMaster"]=isMaster
+
+}
+else {
+ println "mysql_install.groovy: Installing in a standalone mode"
+}
def mysqlHost
@@ -88,6 +192,7 @@ println "mysql_install.groovy: dbPort is ${config.jdbcPort}"
context.attributes.thisInstance["postStartRequired"] = true
+def myCnfObject = getCnfObject(config,context,isMaster,isSlave)
builder = new AntBuilder()
@@ -96,17 +201,17 @@ def currVendor=os.getVendor()
switch (currVendor) {
case ["Ubuntu", "Debian", "Mint"]:
context.attributes.thisInstance["binFolder"]="/usr/bin"
- installLinuxMysql(context,builder,currVendor,"installOnUbuntu.sh")
+ installLinuxMysql(context,builder,currVendor,"installOnUbuntu.sh",myCnfObject)
break
case ["Red Hat", "CentOS", "Fedora", "Amazon",""]:
context.attributes.thisInstance["binFolder"]="/usr/bin"
- installLinuxMysql(context,builder,currVendor,"install.sh")
+ installLinuxMysql(context,builder,currVendor,"install.sh",myCnfObject)
break
case ~/.*(?i)(Microsoft|Windows).*/:
context.attributes.thisInstance["binFolder"]="${osConfig.mysqlHome}/bin"
unzipDir = System.properties["user.home"]+ "/.cloudify/mysql"
zipFullPath="${unzipDir}/${osConfig.zipName}"
- installWindowsMysql(config,osConfig,unzipDir,zipFullPath,builder)
+ installWindowsMysql(config,osConfig,unzipDir,zipFullPath,builder,myCnfObject)
break
default: throw new Exception("Support for ${currVendor} is not implemented")
}
View
4 services/mysql/mysql_query.groovy
@@ -52,7 +52,7 @@ switch (currVendor) {
if (args.length < 3) {
- println "mysql_query.groovy: query error: Missing parameters\nUsage: invoke mysql query actionUser dbName query"
+ println "mysql_query.groovy: query error: Missing parameters\nUsage: invoke serviceName query actionUser dbName query"
System.exit(-1)
}
@@ -62,7 +62,7 @@ def currActionDbName = args[1]
def currQuery = "\"" + args[2] + "\""
def currDebugMsg = "Invoking query: ${currQuery}"
-runMysqlQuery(binFolder,osConfig.mysqlProgram,currOsName,currQuery,currActionDbName,currActionUser,currDebugMsg)
+runMysqlQuery(binFolder,osConfig.mysqlProgram,currOsName,currQuery,currActionDbName,currActionUser,currDebugMsg,"queryOutput",true)
println "mysql_query.groovy: End"
View
84 services/mysql/mysql_runner.groovy
@@ -14,34 +14,45 @@
* limitations under the License.
*******************************************************************************/
import java.text.SimpleDateFormat
-def static runMysqlQuery(binFolder,execFile,osName,currQuery,dbName,dbUser,debugMsg) {
+def static runMysqlQuery(binFolder,execFile,osName,currQuery,dbName,dbUser,debugMsg,outputpropertyName,displayOutputProperty) {
+
+ def outputPropertyStr
+ def builder
try {
- def builder = new AntBuilder()
+ builder = new AntBuilder()
builder.sequential {
echo(message:"runMysqlQuery: os ${osName}: ${debugMsg}")
echo(message:"runMysqlQuery: ${binFolder}/${execFile} -u ${dbUser} -D ${dbName} -e ${currQuery}")
- exec(executable:"${binFolder}/${execFile}", osfamily:"${osName}") {
+ exec(executable:"${binFolder}/${execFile}", osfamily:"${osName}", outputproperty:"${outputpropertyName}") {
arg(line:"-u ${dbUser} -D ${dbName} -e ${currQuery}")
}
}
}
catch (Exception ioe) {
println "runMysqlQuery: Connection Failed!"
ioe.printStackTrace();
- }
+ }
+
+ outputPropertyStr = builder.project.properties."${outputpropertyName}"
+ if ( displayOutputProperty ) {
+ println "runMysqlQuery: outputproperty (${outputpropertyName}) is : ${outputPropertyStr}"
+ }
println "runMysqlQuery: Ended"
+ return outputPropertyStr
}
-def static importMysqlDB(binFolder,execFile,osName,importedFile,dbName,dbUser,debugMsg) {
+def static importMysqlDB(binFolder,execFile,osName,importedFile,dbName,dbUser,debugMsg,outputpropertyName,displayOutputProperty) {
+ def outputPropertyStr
+ def builder
try {
- def builder = new AntBuilder()
+ builder = new AntBuilder()
builder.sequential {
echo(message:"importMysqlDB: ${debugMsg}")
- exec(executable:"${binFolder}/${execFile}", osfamily:"${osName}" ,input:"${importedFile}") {
+ exec(executable:"${binFolder}/${execFile}", osfamily:"${osName}" ,input:"${importedFile}", outputproperty:"${outputpropertyName}") {
arg(value:"-u")
arg(value:"${dbUser}")
arg(value:"${dbName}")
@@ -53,17 +64,24 @@ def static importMysqlDB(binFolder,execFile,osName,importedFile,dbName,dbUser,de
ioe.printStackTrace();
}
+ outputPropertyStr = builder.project.properties."${outputpropertyName}"
+ if ( displayOutputProperty ) {
+ println "importMysqlDB: outputproperty (${outputpropertyName}) is : ${outputPropertyStr}"
+ }
println "importMysqlDB: Ended"
+ return outputPropertyStr
}
-def static runMysqlAdmin(binFolder,execFile,osName,actionName,dbName,dbUser,debugMsg) {
+def static runMysqlAdmin(binFolder,execFile,osName,actionName,dbName,dbUser,debugMsg,outputpropertyName,displayOutputProperty) {
+ def outputPropertyStr
+ def builder
try {
- def builder = new AntBuilder()
+ builder = new AntBuilder()
builder.sequential {
echo(message:"runMysqlAdmin: ${debugMsg}")
- exec(executable:"${binFolder}/${execFile}", osfamily:"${osName}") {
+ exec(executable:"${binFolder}/${execFile}", osfamily:"${osName}", outputproperty:"${outputpropertyName}") {
arg(value:"-u")
arg(value:"${dbUser}")
arg(value:"${actionName}")
@@ -76,10 +94,16 @@ def static runMysqlAdmin(binFolder,execFile,osName,actionName,dbName,dbUser,debu
ioe.printStackTrace();
}
+ outputPropertyStr = builder.project.properties."${outputpropertyName}"
+ if ( displayOutputProperty ) {
+ println "runMysqlAdmin: outputproperty (${outputpropertyName}) is : ${outputPropertyStr}"
+ }
+
println "runMysqlAdmin: Ended"
+ return outputPropertyStr
}
-def static runMysqlDump(binFolder,execFile,osName,actionArgs,dbName,dbUser,debugMsg,dumpFolder,dumpPrefix) {
+def static runMysqlDump(binFolder,execFile,osName,actionArgs,dbName,dbUser,debugMsg,dumpFolder,dumpPrefix) {
try {
@@ -131,8 +155,42 @@ def static importFileToDB(binFolder,osConfig,currOsName,currActionDbName,currImp
def fullPathToImport="${context.serviceDirectory}/${importedFile}"
def currImportFile = new File(fullPathToImport)
def importText = currImportFile.text
- println "groovy: Replacing REPLACE_WITH_DB_NAME with ${config.dbName} in ${context.serviceDirectory}/${importedFile} ..."
+ println "importFileToDB: Replacing REPLACE_WITH_DB_NAME with ${config.dbName} in ${context.serviceDirectory}/${importedFile} ..."
currImportFile.text = importText.replace("REPLACE_WITH_DB_NAME",currActionDbName)
- importMysqlDB(binFolder,osConfig.mysqlProgram,currOsName,fullPathToImport,currActionDbName,currActionUser,currDebugMsg)
+ importMysqlDB(binFolder,osConfig.mysqlProgram,currOsName,fullPathToImport,currActionDbName,currActionUser,currDebugMsg,"dummy",false)
+}
+
+def static showMasterStatus(context,binFolder,execFile,currOsName,currQuery,currActionDbName,currActionUser,currDebugMsg,outputpropertyName,displayOutputProperty) {
+
+ def binLogData = runMysqlQuery(binFolder,execFile,currOsName,currQuery,currActionDbName,currActionUser,currDebugMsg,outputpropertyName,displayOutputProperty)
+
+ def binLogName="mysql-bin"
+
+ println "showMasterStatus: binLogData is "+binLogData
+ println "showMasterStatus: binLogData length is "+binLogData.length()
+
+ if ( binLogData.length() > 0 && binLogData.contains("Position") ) {
+ println "showMasterStatus: splitting binLogData ... "
+ def rawData = binLogData.split(binLogName)[1]
+ println "showMasterStatus: splitting rawData ... "
+ def dataArr = rawData.split()
+
+ println "showMasterStatus: setting binLog ... "
+ def binLog=binLogName+dataArr[0].trim()
+
+ println "showMasterStatus: setting logPos ... "
+ def logPos=dataArr[1].trim()
+
+ println "showMasterStatus: masterBinLogFile is "+binLog
+ println "showMasterStatus: masterBinLogPos is "+logPos
+
+ context.attributes.thisApplication["masterBinLogFile"] = binLog
+ context.attributes.thisApplication["masterBinLogPos"] = logPos
+ return true
+ }
+ else {
+ println "showMasterStatus: master is NOT ready yet"
+ return false
+ }
}
View
92 services/mysql/mysql_showMasterStatus.groovy
@@ -0,0 +1,92 @@
+/*******************************************************************************
+* Copyright (c) 2011 GigaSpaces Technologies Ltd. All rights reserved
+*
+* 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.
+*******************************************************************************/
+import org.hyperic.sigar.OperatingSystem
+import org.cloudifysource.dsl.utils.ServiceUtils;
+import org.cloudifysource.dsl.context.ServiceContextFactory
+import static mysql_runner.*
+
+
+/*
+ This file enables users to invoke an SQL statement
+ Usage : invoke mysql query actionUser dbName query
+ Example: invoke mysql query root myDbName "update users set city=\"NY\" where uid=15"
+*/
+
+config=new ConfigSlurper().parse(new File('mysql-service.properties').toURL())
+osConfig=ServiceUtils.isWindows() ? config.win64 : config.linux
+context = ServiceContextFactory.getServiceContext()
+
+
+if ( !config.masterSlaveMode ) {
+ println "mysql_addSlave.groovy: masterSlaveMode is disabled. I cannot invoke showMasterStatus"
+ System.exit(-1)
+}
+
+def isMaster = context.attributes.thisInstance["isMaster"]
+
+if ( !isMaster ) {
+ println "mysql_showMasterStatus.groovy: I am not a master. I cannot invoke showMasterStatus"
+ System.exit(-1)
+}
+
+
+mysqlHost=context.attributes.thisInstance["dbHost"]
+binFolder=context.attributes.thisInstance["binFolder"]
+println "mysql_showMasterStatus.groovy: mysqlHost is ${mysqlHost} "
+
+def currActionQuery
+def currOsName
+
+def os = OperatingSystem.getInstance()
+def currVendor=os.getVendor()
+switch (currVendor) {
+ case ["Ubuntu", "Debian", "Mint"]:
+ currOsName="unix"
+ break
+ case ["Red Hat", "CentOS", "Fedora", "Amazon",""]:
+ currOsName="unix"
+ break
+ case ~/.*(?i)(Microsoft|Windows).*/:
+ currOsName="windows"
+ break
+ default: throw new Exception("Support for ${currVendor} is not implemented")
+}
+
+
+if (args.length < 2) {
+ println "mysql_showMasterStatus.groovy: showMasterStatus error: Missing parameters\nUsage: invoke serviceName showMasterStatus actionUser dbName"
+ System.exit(-1)
+}
+
+
+def currActionUser = args[0]
+def currActionDbName = args[1]
+def currQuery = "\"" + "show master status;" + "\""
+def currDebugMsg = "Invoking query: ${currQuery}"
+
+def masterStatus = showMasterStatus(context,binFolder,osConfig.mysqlProgram,currOsName,currQuery as String,currActionDbName as String,currActionUser as String,currDebugMsg as String,"binLogData",true)
+
+if ( masterStatus ) {
+ println "mysql_showMasterStatus.groovy: master is up and running"
+}
+else {
+ println "mysql_showMasterStatus.groovy: master is NOT ready yet"
+}
+
+
+println "mysql_showMasterStatus.groovy: End"
+
+
View
128 services/mysql/mysql_start.groovy
@@ -14,6 +14,7 @@
* limitations under the License.
*******************************************************************************/
import org.hyperic.sigar.OperatingSystem
+import java.util.concurrent.TimeUnit
import org.cloudifysource.dsl.utils.ServiceUtils;
import org.cloudifysource.dsl.context.ServiceContextFactory
import static mysql_runner.*
@@ -26,8 +27,6 @@ binFolder=context.attributes.thisInstance["binFolder"]
println "mysql_start.groovy: mysqlHost is ${mysqlHost} "
-
-
def runPostStartActions(config,binFolder,osConfig,currOsName,builder,context,mysqlHost) {
def currActionQuery
def actionCounter = 1
@@ -44,12 +43,12 @@ def runPostStartActions(config,binFolder,osConfig,currOsName,builder,context,mys
case "mysqladmin":
currActionQuery = currActionObj["actionQuery"]
currActionQuery = currActionQuery.replaceAll("MYSQLHOST",mysqlHost)
- runMysqlAdmin(binFolder,osConfig.mysqladmin,currOsName,currActionQuery,currActionDbName,currActionUser,currDebugMsg)
+ runMysqlAdmin(binFolder,osConfig.mysqladmin,currOsName,currActionQuery,currActionDbName,currActionUser,currDebugMsg,"mysqladminOutput",true)
break
case "mysql":
currActionQuery = currActionObj["actionQuery"]
currActionQuery = currActionQuery.replaceAll("MYSQLHOST",mysqlHost)
- runMysqlQuery(binFolder,osConfig.mysqlProgram,currOsName,currActionQuery,currActionDbName,currActionUser,currDebugMsg)
+ runMysqlQuery(binFolder,osConfig.mysqlProgram,currOsName,currActionQuery,currActionDbName,currActionUser,currDebugMsg,"mysqlOutput",true)
break
case "import":
def currImportZip="${context.serviceDirectory}/"+currActionObj["importedZip"]
@@ -72,6 +71,85 @@ def runPostStartActions(config,binFolder,osConfig,currOsName,builder,context,mys
}
}
+
+def addSlaveToMaster(context,config,mysqlHost) {
+
+ while ( !context.attributes.thisService["masterIsReady"] ) {
+ println "mysql_start.groovy: addSlaveToMaster: Slave is waiting for the master..."
+ sleep 10000
+ }
+
+ println "mysql_start.groovy: addSlaveToMaster: Waiting for my future master ..."
+ def mysqlService = context.waitForService("mysql", 180, TimeUnit.SECONDS)
+ def masterInstances = mysqlService.waitForInstances(mysqlService.numberOfActualInstances, 180, TimeUnit.SECONDS)
+
+ def index
+ def currInstance
+ def masterInstance
+ def masterHostAddress
+ def masterID = context.attributes.thisService["masterID"]
+ def instancesCount = masterInstances.length
+ println "mysql_start.groovy: addSlaveToMaster: ${instancesCount} instances are available..."
+ for (index=0; index < instancesCount; index++) {
+ println "mysql_start.groovy: addSlaveToMaster: In loop b4 index ${index} ... "
+ currInstance = masterInstances[index]
+ println "mysql_start.groovy: addSlaveToMaster: In loop after index ${index} currInstance.getInstanceID = " + currInstance.getInstanceID()
+ if ( masterID == currInstance.getInstanceID() ) {
+ masterHostAddress = currInstance.hostAddress
+ masterInstance = currInstance
+ println "mysql_start.groovy: addSlaveToMaster: master instance id is ${masterID}"
+ break;
+ }
+ }
+
+ println "mysql_start.groovy: masterHostAddress is ${masterHostAddress}"
+ println "mysql_start.groovy: addSlaveToMaster: About to invoke addSlave on the master (instance # ${masterID}) ... - Using dbName ${config.dbName}, user ${config.dbUser}, mysqlHost ${mysqlHost} ... "
+ def currActionUser = "root"
+ def currDbName = "${config.dbName}"
+ def currDbUser = "${config.dbUser}"
+ def currDbPassw = "${config.dbPassW}"
+ /* This will grant replication permissions to the slave. */
+ def currResult = masterInstance.invoke("addSlave", currActionUser as String, currDbName as String, currDbUser as String, currDbPassw as String, mysqlHost as String)
+ println "mysql_start.groovy: addSlaveToMaster : addSlave result is ${currResult}"
+ println "mysql_start.groovy: addSlaveToMaster : Invoking addSlave on the master (instance # ${masterID}) ended."
+ return masterHostAddress
+
+}
+
+def changeMasterTo(config,binFolder,osConfig,currOsName,context,masterHost) {
+ println "mysql_start.groovy: In changeMasterTo ..."
+
+ while ( !context.attributes.thisService["masterIsReady"] ) {
+ println "mysql_start.groovy: changeMasterTo: Slave is waiting for the master..."
+ sleep 10000
+ }
+
+ def binLog = context.attributes.thisApplication["masterBinLogFile"]
+ def logPos = context.attributes.thisApplication["masterBinLogPos"]
+ def currActionQuery = "\"" + "CHANGE MASTER TO MASTER_HOST='${masterHost}', MASTER_USER='${config.dbUser}', MASTER_PASSWORD='${config.dbPassW}', MASTER_LOG_FILE='${binLog}', MASTER_LOG_POS=${logPos};" + "\""
+ def currDebugMsg = "About to invoke ${currActionQuery}..."
+ runMysqlQuery(binFolder,osConfig.mysqlProgram,currOsName,currActionQuery,"${config.dbName}","root",currDebugMsg,"changeMasterOutput",true)
+ println "mysql_start.groovy: changeMasterTo Ended"
+}
+
+def startSlave(config,binFolder,osConfig,currOsName) {
+ println "mysql_start.groovy: In startSlave ..."
+ def currActionQuery = "\"" + "start slave;" + "\""
+ def currDebugMsg = "About to invoke ${currActionQuery}..."
+ runMysqlQuery(binFolder,osConfig.mysqlProgram,currOsName,currActionQuery,"${config.dbName}","root",currDebugMsg,"startSlaveOutput",true)
+ println "mysql_start.groovy: startSlave Ended"
+}
+
+def stopSlave(config,binFolder,osConfig,currOsName) {
+ println "mysql_start.groovy: In stopSlave ..."
+ def currActionQuery = "\"" + "stop slave;" + "\""
+ def currDebugMsg = "About to invoke ${currActionQuery}..."
+ runMysqlQuery(binFolder,osConfig.mysqlProgram,currOsName,currActionQuery,"${config.dbName}","root",currDebugMsg,"startSlaveOutput",true)
+ println "mysql_start.groovy: stopSlave Ended"
+}
+
+
+
builder = new AntBuilder()
def os = OperatingSystem.getInstance()
@@ -98,23 +176,57 @@ builder.sequential {
exec(executable:"${script}", osfamily:"${currOsName}",failonerror: "true")
}
-/* Restart does not require postStart, so if attr postStartRequired is false , postStart will NOT be executed. */
+/* Restart does not require postStart, so if the postStartRequired attribute is false , postStart will NOT be executed. */
def postStartRequired = context.attributes.thisInstance["postStartRequired"]
println "mysql_start.groovy: postStartRequired is ${postStartRequired}"
+def masterHost
+
+def isSlave = context.attributes.thisInstance["isSlave"]
+
if ( postStartRequired ) {
try {
println "mysql_start.groovy: postStart"
runPostStartActions(config,binFolder,osConfig,currOsName,builder,context,mysqlHost)
+ if ( config.masterSlaveMode ) {
+ println "mysql_start.groovy: Running in a masterSlaveMode mode"
+ if ( isSlave ) {
+ println "mysql_start.groovy: I am a slave..."
+ masterHost = addSlaveToMaster(context,config,mysqlHost)
+ context.attributes.thisInstance["masterHost"] = masterHost
+ }
+ }
}
catch (Exception ioe) {
println "mysql_start.groovy: Connection Failed!"
println ioe
}
+}
+else {
+ if ( config.masterSlaveMode ) {
+ if ( isSlave ) {
+ masterHost = context.attributes.thisInstance["masterHost"]
+ }
+ }
+}
+
+
+if ( config.masterSlaveMode ) {
+ println "mysql_start.groovy: masterSlaveMode"
+ if ( isSlave ) {
+ println "mysql_start.groovy: I am a slave b4 invoking changeMasterTo..."
+ changeMasterTo(config,binFolder,osConfig,currOsName,context,masterHost)
+ println "mysql_start.groovy: Starting slave threads..."
+ startSlave(config,binFolder,osConfig,currOsName)
+ }
+ else {
+ println "mysql_start.groovy: I am a master..."
+ }
+}
+else {
+ println "mysql_start.groovy: Running in a standalone mode"
}
context.attributes.thisInstance["postStartRequired"] = false
-println "mysql_start.groovy: End"
-
-
+println "mysql_start.groovy: End"
View
55 services/mysql/mysql_startDetection.groovy
@@ -15,13 +15,48 @@
*******************************************************************************/
import org.cloudifysource.dsl.context.ServiceContextFactory
import groovy.sql.*
+import org.hyperic.sigar.OperatingSystem
import org.cloudifysource.dsl.utils.ServiceUtils;
import com.mysql.jdbc.Driver
+import static mysql_runner.*
config=new ConfigSlurper().parse(new File('mysql-service.properties').toURL())
context = ServiceContextFactory.getServiceContext()
+def checkMasterStatus(context,config) {
+ println "mysql_startDetection: checkMasterStatus: I am master ..."
+ osConfig=ServiceUtils.isWindows() ? config.win64 : config.linux
+ binFolder=context.attributes.thisInstance["binFolder"]
+ def currQuery = "\"" + "show master status;" + "\""
+ def currDebugMsg = "Invoking query: ${currQuery}"
+
+ def os = OperatingSystem.getInstance()
+ def currVendor=os.getVendor()
+ switch (currVendor) {
+ case ["Ubuntu", "Debian", "Mint"]:
+ currOsName="unix"
+ break
+ case ["Red Hat", "CentOS", "Fedora", "Amazon",""]:
+ currOsName="unix"
+ break
+ case ~/.*(?i)(Microsoft|Windows).*/:
+ currOsName="windows"
+ break
+ default: throw new Exception("Support for ${currVendor} is not implemented")
+ }
+
+ def masterStatus = showMasterStatus(context,binFolder,osConfig.mysqlProgram,currOsName,currQuery,config.dbName,"root",currDebugMsg,"binLogData",true)
+ if (masterStatus) {
+ println "mysql_startDetection: checkMasterStatus: master is ready "
+ return true
+ }
+ else {
+ println "mysql_startDetection: checkMasterStatus: master is NOT ready yet..."
+ return false
+ }
+}
+
println "mysql_startDetection.groovy: jdbcPort is ${config.jdbcPort} ..."
if ( ServiceUtils.isPortOccupied(config.jdbcPort) ) {
println "mysql_startDetection: port ${config.jdbcPort} is now occupied ..."
@@ -51,8 +86,26 @@ if ( ServiceUtils.isPortOccupied(config.jdbcPort) ) {
def cc = row0["cc"] as int
context.attributes.thisInstance["cc"] = cc
println "mysql_startDetection: Count " + cc
- //return cc > 0
if ( cc > 0 ) {
+ if ( config.masterSlaveMode ) {
+ println "mysql_startDetection: in master-slave Mode ..."
+ def isMaster = context.attributes.thisInstance["isMaster"]
+ println "mysql_startDetection: isMaster is ${isMaster}..."
+ if ( isMaster ) {
+ if (checkMasterStatus(context,config)) {
+ println "mysql_startDetection: Master is ready"
+ context.attributes.thisService["masterIsReady"]=true
+ System.exit(0)
+ }
+ else {
+ println "mysql_startDetection: Master is NOT ready yet..."
+ System.exit(-1)
+ }
+ }
+ }
+ else {
+ println "mysql_startDetection: in standalone mode ..."
+ }
System.exit(0)
}
else {

0 comments on commit 969b16f

Please sign in to comment.