diff --git a/README.rst b/README.rst index 92c2b81..a5e9072 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,10 @@ Repository with murano metadata Murano project on launchpad https://launchpad.net/murano +INSTALL FROM SOURCE +===================== +Please, use setup.sh script with root user privileges for install/uninstall of the software. + License ------- Copyright (c) 2013 Mirantis Inc. diff --git a/common.inc b/common.inc new file mode 100644 index 0000000..ed7b662 --- /dev/null +++ b/common.inc @@ -0,0 +1,379 @@ +#!/bin/bash +# +# Common functions file +# +DEBUGLVL=2 +RUN_DIR=${RUN_DIR:-$(cd $(dirname "$0") && pwd)} +LOGFILE="$RUN_DIR/install.log" +PIPAPPS="pip python-pip pip-python" +PIPCMD="" +PIPARGS="" +TRBL_FILE="" + +if [ "$DEBUGLVL" -eq 4 ]; then + set -x +fi +function log { + if [ "$DEBUGLVL" -gt 0 ]; then + chars=$(echo "@$" | wc -c) + case $DEBUGLVL in + 1) + echo -e "LOG:>$@" + ;; + 2) + echo -e "$(date +"%m-%d-%Y %H:%M") LOG:>$@" | tee --append $LOGFILE + ;; + 3) + echo -e "$(date +"%m-%d-%Y %H:%M") LOG:>$@" >> $LOGFILE + ;; + 4) + echo -e "$(date +"%m-%d-%Y %H:%M") LOG:>$@" | tee --append $LOGFILE + ;; + esac + fi +} +function lowercase(){ + echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" +} +function get_os(){ + KERNEL=$(uname -r) + MACH=$(uname -m) + OS=$(uname) + if [ "${OS}" = "Linux" ] ; then + if [ -f /etc/redhat-release ] ; then + DISTRO_BASED_ON='RedHat' + PACKAGER='yum' + PKG_MGR='rpm' + DIST=$(cat /etc/redhat-release |sed s/\ release.*//) + PSUEDONAME=$(cat /etc/redhat-release | sed s/.*\(// | sed s/\)//) + REV=$(cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//) + elif [ -f /etc/SuSE-release ] ; then + DISTRO_BASED_ON='SuSe' + PACKAGER='zypper' + PKG_MGR='rpm' + PSUEDONAME=$(cat /etc/SuSE-release | tr "\n" ' '| sed s/VERSION.*//) + REV=$(cat /etc/SuSE-release | tr "\n" ' ' | sed s/.*=\ //) + elif [ -f /etc/debian_version ] ; then + DISTRO_BASED_ON='Debian' + PACKAGER='apt-get' + PKG_MGR='dpkg' + DIST=$(cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F= '{ print $2 }') + PSUEDONAME=$(cat /etc/lsb-release | grep '^DISTRIB_CODENAME' | awk -F= '{ print $2 }') + REV=$(cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F= '{ print $2 }') + fi + if [ -f /etc/UnitedLinux-release ] ; then + DIST="${DIST}[$(cat /etc/UnitedLinux-release | tr "\n" ' ' | sed s/VERSION.*//)]" + fi + OS=$(lowercase $OS) + DISTRO_BASED_ON=$(lowercase $DISTRO_BASED_ON) + readonly OS + readonly DIST + readonly DISTRO_BASED_ON + readonly PSUEDONAME + readonly REV + readonly KERNEL + readonly MACH + #readonly PACKAGER + else + OS=unknown + readonly OS + log "Unsupported OS:\"$OS\", sorry, exiting!" + exit 1 + fi +} +function find_or_install() +{ + _searching_for=$1 + _pkg_mrg_cmd='' + _pkgr_cmd='' + retval=0 + case $(lowercase $DISTRO_BASED_ON) in + "debian") + _pkg_mrg_cmd="$PKG_MGR -s $_searching_for" + _pkgr_cmd="$PACKAGER install $_searching_for --yes" + ;; + *) + _pkg_mrg_cmd="$PKG_MGR -q $_searching_for" + _pkgr_cmd="$PACKAGER install $_searching_for -y" + ;; + esac + $_pkg_mrg_cmd > /dev/null 2>&1 + if [ $? -eq 0 ]; then + log "Package \"$_searching_for\" already installed" + retval=2 + else + log "Installing \"$_searching_for\"..." + $_pkgr_cmd > /dev/null 2>&1 + if [ $? -ne 0 ];then + log "...installation fails, exiting!" + retval=1 + else + log "...success" + retval=0 + fi + fi + return $retval +} +function is_py_package_installed() +{ + retval=0 + py_pkg=$1 + found_pkg=$($PIPCMD freeze | grep -E "^$py_pkg") + if [ $? -ne 0 ]; then + retval=1 + fi + echo $found_pkg + return $retval +} +function genpass() +{ + echo $(date | md5sum |head -c${5:-13}) +} +function shslash() +{ + echo $1 | sed 's/\//\\\//g' +} +function split() +{ + # Prefix local names with the function name to try to avoid conflicts + # local split_wordlist + split_wordlist="$1" + shift + read "$@" <= v2, false if v1 < v2 +function version_ge() +{ + # Prefix local names with the function name to try to avoid conflicts + # local version_ge_1 version_ge_2 version_ge_a version_ge_b + # local version_ge_save_ifs + version_ge_v1="$1" + version_ge_v2="$2" + version_ge_save_ifs="$IFS" + while test -n "${version_ge_v1}${version_ge_v2}"; do + IFS="." + split "$version_ge_v1" version_ge_a version_ge_v1 + split "$version_ge_v2" version_ge_b version_ge_v2 + IFS="$version_ge_save_ifs" + #echo " compare $version_ge_a $version_ge_b" + test "0$version_ge_a" -gt "0$version_ge_b" && return 0 # v1>v2: true + test "0$version_ge_a" -lt "0$version_ge_b" && return 1 # v1/dev/null) + if [ $? -eq 0 ];then + break + fi + done + if [ -z "$_cmd" ];then + echo "Can't find \"pip\" in system, please install it first, exiting!" + exit 1 + else + _pip_ver=$($_cmd --version | grep -oE "[0-9]\.[0-9]" | head -n1) + if [ -n "$_pip_ver" ]; then + version_ge $_pip_ver $pip_min_ver + if [ $? -ne 0 ]; then + log "Upgrading pip ..." + $_cmd install --upgrade pip==$pip_min_ver + if [ $? -ne 0 ]; then + log "...pip upgrade fails, exiting!" + exit 1 + else + log "...success" + sleep 2 + for cmd in $PIPAPPS + do + _cmd=$(which $cmd 2>/dev/null) + if [ $? -eq 0 ];then + break + fi + done + fi + fi + _pip_ver=$($_cmd --version | grep -oE "[0-9]\.[0-9]" | head -n1) + version_ge $_pip_ver "1.5" + if [ $? -eq 0 ]; then + log "For future use, sorry, use pip v$pip_min_ver, exiting!" + exit 1 + ##_pipargs="--allow-unverified --allow-external" + #_pipargs="--allow-all-external" + #mk_dir "/root/.pip" + #_pipcfg="/root/.pip/pip.conf" + #if [ ! -f "$_pipcfg" ]; then + # touch $_pipcfg + #fi + #iniset 'install' 'allow-all-external' 'true' "$_pipcfg" + #iniset 'install' 'allow-all-unverified' 'true' "$_pipcfg" + #log "Setuptools upgrade required..." + #$cmd install setuptools --no-use-wheel --upgrade >> $LOGFILE 2>&1 + #if [ $? -ne 0 ]; then + # log "...upgrade fails, exiting" + # exit 1 + #else + # log "...success" + #fi + fi + log "Found pip version - $_pip_ver" + fi + PIPARGS=$_pipargs + PIPCMD=$_cmd + fi +} +function add_daemon_credentials() +{ + retval=0 + daemonuser=${1:-murano} + daemongroup=${2:-murano} + daemonhomedir=${3:-/home/$daemonuser} + getent group $daemongroup > /dev/null + if [ $? -ne 0 ]; then + log "Creating group \"$daemongroup\"..." + groupadd -r $daemongroup + if [ $? -eq 0 ]; then + log "...success" + else + log "Can't create \"$daemongroup\", exiting!" + retval=1 + exit 1 + fi + else + log "Group \"$daemongroup\" exists" + fi + getent passwd $daemonuser > /dev/null + if [ $? -ne 0 ]; then + log "Creating user \"$daemonuser\"..." + useradd -r -g $daemongroup -G $daemongroup -d $daemonhomedir -s $(which nologin) -c "Murano Daemons" $daemonuser + if [ $? -eq 0 ]; then + log "...success" + else + log "Can't create \"$daemonuser\", exiting!" + retval=1 + exit 1 + fi + else + log "User \"$daemonuser\" exists" + fi + return $retval +} +function remove_daemon_credentials() +{ + retval=0 + daemonuser=${1:-murano} + daemongroup=${2:-murano} + daemonhomedir=${3:-/home/$daemonuser} + getent passwd $daemonuser > /dev/null + if [ $? -eq 0 ]; then + log "Deleting user \"$daemonuser\"..." + userdel -f $daemonuser + if [ $? -eq 0 ]; then + if [ -d "$daemonhomedir" ]; then + rm -rf $daemonhomedir + fi + log "...success" + else + log "Can't delete \"$daemonuser\", exiting!" + retval=1 + exit 1 + fi + fi + getent group $daemongroup > /dev/null + if [ $? -eq 0 ]; then + log "Deleting group \"$daemongroup\"..." + groupdel $daemongroup + if [ $? -eq 0 ]; then + log "...success" + else + log "Can't delete \"$daemongroup\", exiting!" + retval=1 + exit 1 + fi + fi + return $retval +} +function iniset() +{ + local section=$1 + local option=$2 + local value=$3 + local file=$4 + local line + + if [ -z "$section" ] ; then + # No section name specified + sed -i -e "s/^\($option[ \t]*=[ \t]*\).*$/\1$value/" "$file" + else + # Check if section already exists + if ! grep -q "^\[$section\]" "$file" ; then + # Add section at the end + echo -e "\n[$section]" >>"$file" + fi + + # Check if parameter in the section exists + line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file") + if [ -z "$line" ] ; then + # Add parameter if it is not exists + sed -i -e "/^\[$section\]/ a\\ +$option = $value +" "$file" + else + # Replace existing parameter + sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=[ \t]*\).*$|\1$value|" "$file" + fi + fi +} +function mk_dir() +{ + retval=0 + path_to_check=$1 + if [ -d "$path_to_check" ]; then + log "Path \"$path_to_check\" already exists." + elif [ -f "$path_to_check" ]; then + log "Path \"path_to_check\" is an existing file, exiting!" + exit 1 + else + mkdir -p "$path_to_check" + if [ $? -ne 0 ]; then + log "Can't create \"$path_to_check\", exiting!" + retval=1 + exit 1 + fi + fi + if [ $# -eq 3 ]; then + owner_user=$2 + owner_group=$3 + chown -R $owner_user:$owner_group $path_to_check + if [ $? -ne 0 ]; then + log "Can't set ownership to \"$owner_user:$owner_group\" for \"$path_to_check\", exiting!" + retval=1 + exit 1 + fi + fi + return $retval +} +function get_service_exec_path() +{ + retval=0 + if [ -z "$SERVICE_EXEC_PATH" ]; then + SERVICE_EXEC_PATH=$(which $DAEMON_NAME) + if [ $? -ne 0 ]; then + log "Can't find \"$DAEMON_NAME\", please install the \"$SERVICE_SRV_NAME\" by running \"$(basename "$0") install\" or set variable SERVICE_EXEC_PATH=/path/to/daemon before running setup script, exiting!" + retval=1 + fi + else + if [ ! -x "$SERVICE_EXEC_PATH" ]; then + log "\"$SERVICE_EXEC_PATH\" in not executable, please install the \"$DAEMON_NAME\" or set variable SERVICE_EXEC_PATH=/path/to/daemon before running setup script, exiting!" + retval=1 + fi + fi + return $retval +} diff --git a/etc/init.d/README.rst b/etc/init.d/README.rst new file mode 100644 index 0000000..236d5fe --- /dev/null +++ b/etc/init.d/README.rst @@ -0,0 +1,4 @@ +SysV init scripts +===================== +murano-repository-redhat - for RedHat based Linux distibution +murano-repository-debian - for Debian based Linux distibution diff --git a/etc/init.d/murano-repository-debian b/etc/init.d/murano-repository-debian new file mode 100644 index 0000000..112639e --- /dev/null +++ b/etc/init.d/murano-repository-debian @@ -0,0 +1,104 @@ +#!/bin/sh +# Copyright (c) 2014 Mirantis, Inc. +# +# 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. +# Author: Igor Yozhikov +# +### BEGIN INIT INFO +# Provides: murano-repository +# Required-Start: $network $local_fs $remote_fs $syslog +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenStack Murano Respository Service +# Description: This startup script launches murano-repository service daemon. +### END INIT INFO + + +PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin +DESC="murano-repository" +NAME=murano-repository +DAEMON=$(which murano-repository) +PIDFILE=/var/run/murano/$NAME.pid +SCRIPTNAME=/etc/init.d/openstack-$NAME +SYSTEM_USER=murano +CONFIG_FILE=/etc/murano/murano-repository.conf +# Exit if the package is not installed +[ -x $DAEMON ] || exit 5 + +# source function library +. /lib/lsb/init-functions + + + +do_start() +{ + if [ ! -d "/var/run/murano" ]; then + mkdir -p /var/run/murano + chown -R $SYSTEM_USER /var/run/murano + fi + start-stop-daemon --start --background --quiet --chuid $SYSTEM_USER:$SYSTEM_USER --make-pidfile --pidfile $PIDFILE --startas $DAEMON --test -- --config-file=$CONFIG_FILE > /dev/null || return 1 + start-stop-daemon --start --background --quiet --chuid $SYSTEM_USER:$SYSTEM_USER --make-pidfile --pidfile $PIDFILE --startas $DAEMON -- --config-file=$CONFIG_FILE || return 2 +} + +do_stop() +{ + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE + RETVAL="$?" + rm -f $PIDFILE + return "$RETVAL" +} + +case "$1" in + start) + log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + restart|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac diff --git a/etc/init.d/murano-repository-redhat b/etc/init.d/murano-repository-redhat new file mode 100644 index 0000000..6872232 --- /dev/null +++ b/etc/init.d/murano-repository-redhat @@ -0,0 +1,102 @@ +#!/bin/sh +# Copyright (c) 2014 Mirantis, Inc. +# +# 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. +# Author: Igor Yozhikov +# +### BEGIN INIT INFO +# Provides: murano-repository +# Required-Start: $network $local_fs $remote_fs $syslog +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenStack Murano Respository Service +# Description: This startup script launches murano-repository service daemon. +### END INIT INFO +# chkconfig: 3 90 10 +# description: This startup script launches murano-repository service daemon. +# config: /etc/murano/murano-repository.conf +# +PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin +DESC="murano-repository" +NAME=murano-repository +DAEMON=$(which murano-repository) +PIDFILE=/var/run/murano/$NAME.pid +SCRIPTNAME=/etc/init.d/openstack-$NAME +SYSTEM_USER=murano +CONFIG_FILE=/etc/murano/murano-repository.conf +LOCKFILE=/var/lock/subsys/$NAME +# Exit if the package is not installed +[ -x $DAEMON ] || exit 5 + +# source function library +. /etc/init.d/functions + +RETVAL=0 + + +start() { + if [ ! -d "/var/run/murano" ]; then + mkdir -p /var/run/murano + chown -R $SYSTEM_USER /var/run/murano + fi + echo -n "Starting $NAME: " + daemon --user $SYSTEM_USER "$DAEMON --config-file=$CONFIG_FILE &>/dev/null & echo \$! > $PIDFILE" + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && touch $LOCKFILE + return $RETVAL +} + +stop() { + echo -n "Stopping $NAME: " + #killproc $DAEMON -TERM + killproc -p $PIDFILE $DAEMON + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && rm -f $LOCKFILE + return $RETVAL +} + +restart() { + stop + start +} + +rh_status() { + # run checks to determine if the service is running or use generic status + status $DAEMON +} + + +case "$1" in + start) + start + ;; + + stop) + stop + ;; + + restart) + restart + ;; + + status) + rh_status + ;; + *) + echo $"Usage: $0 {start|stop|status|restart}" + exit 2 +esac +exit $? diff --git a/etc/murano-repository.conf.sample b/etc/murano-repository.conf.sample index e1b408b..b098466 100644 --- a/etc/murano-repository.conf.sample +++ b/etc/murano-repository.conf.sample @@ -13,8 +13,10 @@ verbose = True # Show debugging output in logs (sets DEBUG log level output) debug = True -# Log to this file. Make sure the user has permissions to write to this file! +# Set up logging. To use syslog just set use_syslog parameter value to 'True'. log_file = /tmp/murano-repository.log +use_syslog = False +syslog_log_facility = LOG_LOCAL0 # Provide information about data types # absolute or relative path to manifest location(root directory) diff --git a/muranorepository/Services/agent_templates/SqlServerCluster/ConfigureEnvironmentForAOAG.template b/muranorepository/Services/agent_templates/SqlServerCluster/ConfigureEnvironmentForAOAG.template index df12ddf..28ddc67 100644 --- a/muranorepository/Services/agent_templates/SqlServerCluster/ConfigureEnvironmentForAOAG.template +++ b/muranorepository/Services/agent_templates/SqlServerCluster/ConfigureEnvironmentForAOAG.template @@ -1,6 +1,6 @@ { "Scripts": [ - "ImportCoreFunctions.ps1", + "/ImportCoreFunctions.ps1", "SQLServerForAOAG.ps1" ], "Commands": [ diff --git a/muranorepository/Services/agent_templates/SqlServerCluster/FailoverCluster.template b/muranorepository/Services/agent_templates/SqlServerCluster/FailoverCluster.template index f345e36..365bf0f 100644 --- a/muranorepository/Services/agent_templates/SqlServerCluster/FailoverCluster.template +++ b/muranorepository/Services/agent_templates/SqlServerCluster/FailoverCluster.template @@ -1,7 +1,7 @@ { "Scripts": [ - "ImportCoreFunctions.ps1", - "Start-PowerShellProcess.ps1", + "/ImportCoreFunctions.ps1", + "/Start-PowerShellProcess.ps1", "Failover-Cluster.ps1" ], "Commands": [ diff --git a/muranorepository/Services/agent_templates/SqlServerCluster/FailoverClusterPrerequisites.template b/muranorepository/Services/agent_templates/SqlServerCluster/FailoverClusterPrerequisites.template index e439f54..3c63f11 100644 --- a/muranorepository/Services/agent_templates/SqlServerCluster/FailoverClusterPrerequisites.template +++ b/muranorepository/Services/agent_templates/SqlServerCluster/FailoverClusterPrerequisites.template @@ -1,7 +1,7 @@ { "Scripts": [ - "ImportCoreFunctions.ps1", - "Update-ServiceConfig.ps1", + "/ImportCoreFunctions.ps1", + "/Update-ServiceConfig.ps1", "SQLServerForAOAG.ps1", "Failover-Cluster.ps1" ], diff --git a/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAOAGPrimaryReplica.template b/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAOAGPrimaryReplica.template index d98eae5..e70d880 100644 --- a/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAOAGPrimaryReplica.template +++ b/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAOAGPrimaryReplica.template @@ -1,11 +1,11 @@ { "Scripts": [ - "ImportCoreFunctions.ps1", - "OptionParser.ps1", - "SQLServer/SQLServerOptionParsers.ps1", - "SQLServer/SQLServerInstaller.ps1", - "Export-Function.ps1", - "Start-PowerShellProcess.ps1", + "/ImportCoreFunctions.ps1", + "/OptionParser.ps1", + "/SQLServer/SQLServerOptionParsers.ps1", + "/SQLServer/SQLServerInstaller.ps1", + "/Export-Function.ps1", + "/Start-PowerShellProcess.ps1", "SQLServerForAOAG.ps1" ], "Commands": [ diff --git a/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAOAGSecondaryReplica.template b/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAOAGSecondaryReplica.template index 4d55aa6..18bee96 100644 --- a/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAOAGSecondaryReplica.template +++ b/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAOAGSecondaryReplica.template @@ -1,11 +1,11 @@ { "Scripts": [ - "ImportCoreFunctions.ps1", - "OptionParser.ps1", - "SQLServer/SQLServerOptionParsers.ps1", - "SQLServer/SQLServerInstaller.ps1", - "Export-Function.ps1", - "Start-PowerShellProcess.ps1", + "/ImportCoreFunctions.ps1", + "/OptionParser.ps1", + "/SQLServer/SQLServerOptionParsers.ps1", + "/SQLServer/SQLServerInstaller.ps1", + "/Export-Function.ps1", + "/Start-PowerShellProcess.ps1", "SQLServerForAOAG.ps1" ], "Commands": [ diff --git a/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAlwaysOn.template b/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAlwaysOn.template index ce0f1b9..83317d2 100644 --- a/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAlwaysOn.template +++ b/muranorepository/Services/agent_templates/SqlServerCluster/InitializeAlwaysOn.template @@ -1,11 +1,11 @@ { "Scripts": [ - "ImportCoreFunctions.ps1", - "OptionParser.ps1", - "SQLServer/SQLServerOptionParsers.ps1", - "SQLServer/SQLServerInstaller.ps1", - "Export-Function.ps1", - "Start-PowerShellProcess.ps1", + "/ImportCoreFunctions.ps1", + "/OptionParser.ps1", + "/SQLServer/SQLServerOptionParsers.ps1", + "/SQLServer/SQLServerInstaller.ps1", + "/Export-Function.ps1", + "/Start-PowerShellProcess.ps1", "SQLServerForAOAG.ps1" ], "Commands": [ diff --git a/muranorepository/Services/agent_templates/SqlServerCluster/InstallSqlServerForAOAG.template b/muranorepository/Services/agent_templates/SqlServerCluster/InstallSqlServerForAOAG.template index 7e66ef2..72f8b9d 100644 --- a/muranorepository/Services/agent_templates/SqlServerCluster/InstallSqlServerForAOAG.template +++ b/muranorepository/Services/agent_templates/SqlServerCluster/InstallSqlServerForAOAG.template @@ -1,9 +1,9 @@ { "Scripts": [ - "ImportCoreFunctions.ps1", - "OptionParser.ps1", - "SQLServer/SQLServerOptionParsers.ps1", - "SQLServer/SQLServerInstaller.ps1", + "/ImportCoreFunctions.ps1", + "/OptionParser.ps1", + "/SQLServer/SQLServerOptionParsers.ps1", + "/SQLServer/SQLServerInstaller.ps1", "SQLServerForAOAG.ps1" ], "Commands": [ diff --git a/muranorepository/Services/aspNetApp-manifest.yaml b/muranorepository/Services/aspNetApp-manifest.yaml index 1c645f0..3143f57 100644 --- a/muranorepository/Services/aspNetApp-manifest.yaml +++ b/muranorepository/Services/aspNetApp-manifest.yaml @@ -30,6 +30,7 @@ heat: - DefaultSecurity.template - WindowsSecurity.template - WebServerSecurity.template + - FloatingIP.template agent: - SetPassword.template diff --git a/muranorepository/Services/aspNetAppFarm-manifest.yaml b/muranorepository/Services/aspNetAppFarm-manifest.yaml index aee9476..d121e3e 100644 --- a/muranorepository/Services/aspNetAppFarm-manifest.yaml +++ b/muranorepository/Services/aspNetAppFarm-manifest.yaml @@ -31,6 +31,7 @@ heat: - DefaultSecurity.template - WindowsSecurity.template - WebServerSecurity.template + - FloatingIPwithLB.template agent: - SetPassword.template diff --git a/muranorepository/Services/heat_templates/DomainSecurity.template b/muranorepository/Services/heat_templates/DomainSecurity.template index e234739..6e7fb4c 100644 --- a/muranorepository/Services/heat_templates/DomainSecurity.template +++ b/muranorepository/Services/heat_templates/DomainSecurity.template @@ -5,93 +5,135 @@ "Properties": { "SecurityGroupIngress": [ { + "IpProtocol": "tcp", + "FromPort": "25", + "ToPort": "25", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "53", + "ToPort": "53", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "53", + "ToPort": "53", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "88", + "ToPort": "88", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "88", + "ToPort": "88", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "123", "ToPort": "123", - "IpProtocol": "udp", - "FromPort": "53", "CidrIp": "$cidr" }, { + "IpProtocol": "tcp", + "FromPort": "135", "ToPort": "135", - "IpProtocol": "tcp", - "FromPort": "53", "CidrIp": "$cidr" }, { - "ToPort": "464", - "IpProtocol": "tcp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { - "ToPort": "464", "IpProtocol": "udp", - "FromPort": "53", + "FromPort": "137", + "ToPort": "137", "CidrIp": "$cidr" }, { - "ToPort": "389", - "IpProtocol": "tcp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { - "ToPort": "389", "IpProtocol": "udp", - "FromPort": "53", + "FromPort": "138", + "ToPort": "138", "CidrIp": "$cidr" }, { - "ToPort": "636", "IpProtocol": "tcp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { - "ToPort": "3268", - "IpProtocol": "tcp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { - "ToPort": "3269", - "IpProtocol": "tcp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { - "ToPort": "53", - "IpProtocol": "tcp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { - "ToPort": "53", - "IpProtocol": "udp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { - "ToPort": "88", - "IpProtocol": "tcp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { - "ToPort": "88", - "IpProtocol": "udp", - "FromPort": "53", - "CidrIp": "$cidr" - }, - { + "FromPort": "445", "ToPort": "445", - "IpProtocol": "tcp", - "FromPort": "53", "CidrIp": "$cidr" }, { - "ToPort": "65535", + "IpProtocol": "udp", + "FromPort": "445", + "ToPort": "445", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "464", + "ToPort": "464", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "464", + "ToPort": "464", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "389", + "ToPort": "389", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "389", + "ToPort": "389", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "636", + "ToPort": "636", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "3268", + "ToPort": "3268", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "3269", + "ToPort": "3269", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "5722", + "ToPort": "5722", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "9389", + "ToPort": "9389", + "CidrIp": "$cidr" + }, + { "IpProtocol": "tcp", "FromPort": "49152", + "ToPort": "65535", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "49152", + "ToPort": "65535", "CidrIp": "$cidr" } ] diff --git a/muranorepository/Services/heat_templates/FloatingIP.template b/muranorepository/Services/heat_templates/FloatingIP.template new file mode 100644 index 0000000..e428be9 --- /dev/null +++ b/muranorepository/Services/heat_templates/FloatingIP.template @@ -0,0 +1,24 @@ +{ + "Resources": { + "${instanceName}-FloatingIP": { + "Type": "OS::Neutron::FloatingIP", + "Properties": { + "floating_network_id": "$externalNetworkId" + } + }, + "${instanceName}-FloatingIpAssoc": { + "Type": "OS::Neutron::FloatingIPAssociation", + "Properties": { + "floatingip_id": { "Ref" : "${instanceName}-FloatingIP" }, + "port_id": { "Ref" : "$instancePort" } + } + } + }, + "Outputs": { + "${instanceName}-FloatingIPaddress": { + "Value": {"Fn::GetAtt": ["${instanceName}-FloatingIP", "floating_ip_address"]}, + "Description": "Floating IP assigned" + } + } +} + diff --git a/muranorepository/Services/heat_templates/FloatingIPwithLB.template b/muranorepository/Services/heat_templates/FloatingIPwithLB.template new file mode 100644 index 0000000..6b3b657 --- /dev/null +++ b/muranorepository/Services/heat_templates/FloatingIPwithLB.template @@ -0,0 +1,23 @@ +{ + "Resources": { + "${instanceName}-FloatingIP": { + "Type": "OS::Neutron::FloatingIP", + "Properties": { + "floating_network_id": "$externalNetworkId" + } + }, + "${instanceName}-FloatingIpAssoc": { + "Type": "OS::Neutron::FloatingIPAssociation", + "Properties": { + "floatingip_id": { "Ref" : "${instanceName}-FloatingIP" }, + "port_id": {"Fn::Select": ["port_id", {"Fn::GetAtt": ["${lbName}-Pool", "vip"]}]} + } + } + }, + "Outputs": { + "${instanceName}-FloatingIPaddress": { + "Value": {"Fn::GetAtt": ["${instanceName}-FloatingIP", "floating_ip_address"]}, + "Description": "Floating IP assigned" + } + } +} diff --git a/muranorepository/Services/heat_templates/LoadBalancer.template b/muranorepository/Services/heat_templates/LoadBalancer.template index 4d3a4f6..7d94caf 100644 --- a/muranorepository/Services/heat_templates/LoadBalancer.template +++ b/muranorepository/Services/heat_templates/LoadBalancer.template @@ -21,7 +21,6 @@ "name": "${lbName}-Pool", "vip": { "name": "${lbName}-Pool-VIP", - "address": "$lbIp", "protocol_port": "$lbPort" }, "monitors": [{"Ref": "${lbName}-HealthMonitor"}] @@ -35,5 +34,11 @@ "members": [{"Ref": "$instanceName"}] } } + }, + "Outputs": { + "${lbName}-loadBalancerIp": { + "Value": {"Fn::Select": ["address", {"Fn::GetAtt": ["${lbName}-Pool", "vip"]}]}, + "Description": "IP assigned to VIP" + } } } diff --git a/muranorepository/Services/heat_templates/SQL-security.template b/muranorepository/Services/heat_templates/SQL-security.template index e4196cd..ffcf5d9 100644 --- a/muranorepository/Services/heat_templates/SQL-security.template +++ b/muranorepository/Services/heat_templates/SQL-security.template @@ -5,22 +5,34 @@ "Properties": { "SecurityGroupIngress": [ { - "ToPort": "4022", - "IpProtocol": "tcp", - "FromPort": "4022", - "CidrIp": "$cidr" - }, - { - "ToPort": "135", "IpProtocol": "tcp", "FromPort": "135", + "ToPort": "135", "CidrIp": "$cidr" }, { - "ToPort": "1433", "IpProtocol": "tcp", "FromPort": "1433", + "ToPort": "1433", "CidrIp": "0.0.0.0/0" + }, + { + "IpProtocol": "udp", + "FromPort": "1434", + "ToPort": "1434", + "CidrIp": "0.0.0.0/0" + }, + { + "IpProtocol": "tcp", + "FromPort": "4022", + "ToPort": "4022", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "49152", + "ToPort": "65535", + "CidrIp": "$cidr" } ] } diff --git a/muranorepository/Services/heat_templates/WSFCSecurity.template b/muranorepository/Services/heat_templates/WSFCSecurity.template new file mode 100644 index 0000000..6e1bf19 --- /dev/null +++ b/muranorepository/Services/heat_templates/WSFCSecurity.template @@ -0,0 +1,41 @@ +{ + "Resources": { + "$MuranoSecurityGroup-{envName}": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "SecurityGroupIngress": [ + { + "IpProtocol": "tcp", + "FromPort": "135", + "ToPort": "135", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "137", + "ToPort": "137", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "tcp", + "FromPort": "3343", + "ToPort": "3343", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "3343", + "ToPort": "3343", + "CidrIp": "$cidr" + }, + { + "IpProtocol": "udp", + "FromPort": "49152", + "ToPort": "65535", + "CidrIp": "$cidr" + } + ] + } + } + } +} diff --git a/muranorepository/Services/linuxApacheService-manifest.yaml b/muranorepository/Services/linuxApacheService-manifest.yaml index fec21ed..cdabe72 100644 --- a/muranorepository/Services/linuxApacheService-manifest.yaml +++ b/muranorepository/Services/linuxApacheService-manifest.yaml @@ -31,6 +31,7 @@ heat: - WebServerSecurity.template - LinuxSecurity.template - Keypair.template + - FloatingIP.template agent: - DeployApache.template diff --git a/muranorepository/Services/linuxTelnetService-manifest.yaml b/muranorepository/Services/linuxTelnetService-manifest.yaml index 31e6b02..04c3a2e 100644 --- a/muranorepository/Services/linuxTelnetService-manifest.yaml +++ b/muranorepository/Services/linuxTelnetService-manifest.yaml @@ -30,6 +30,7 @@ heat: - LinuxSecurity.template - TelnetSecurity.template - Keypair.template + - FloatingIP.template agent: - DeployTelnet.template diff --git a/muranorepository/Services/msSqlClusterServer-manifest.yaml b/muranorepository/Services/msSqlClusterServer-manifest.yaml index 9ed82a3..593f516 100644 --- a/muranorepository/Services/msSqlClusterServer-manifest.yaml +++ b/muranorepository/Services/msSqlClusterServer-manifest.yaml @@ -31,6 +31,7 @@ heat: - DefaultSecurity.template - WindowsSecurity.template - SQL-security.template + - WSFCSecurity.template agent: @@ -48,8 +49,8 @@ scripts: - ImportCoreFunctions.ps1 - Set-LocalUserPassword.ps1 - Update-ServiceConfig.ps1 - - SQLServerForAOAG.ps1 - - Failover-Cluster.ps1 + - SqlServerCluster/SQLServerForAOAG.ps1 + - SqlServerCluster/Failover-Cluster.ps1 - Start-PowerShellProcess.ps1 - OptionParser.ps1 - SQLServer/SQLServerOptionParsers.ps1 diff --git a/muranorepository/Services/msSqlServer-manifest.yaml b/muranorepository/Services/msSqlServer-manifest.yaml index 9c84eb3..8c39326 100644 --- a/muranorepository/Services/msSqlServer-manifest.yaml +++ b/muranorepository/Services/msSqlServer-manifest.yaml @@ -31,6 +31,7 @@ heat: - DefaultSecurity.template - WindowsSecurity.template - SQL-security.template + - FloatingIP.template agent: diff --git a/muranorepository/Services/scripts/Failover-Cluster.ps1 b/muranorepository/Services/scripts/SqlServerCluster/Failover-Cluster.ps1 similarity index 96% rename from muranorepository/Services/scripts/Failover-Cluster.ps1 rename to muranorepository/Services/scripts/SqlServerCluster/Failover-Cluster.ps1 index e444ac2..e082994 100644 --- a/muranorepository/Services/scripts/Failover-Cluster.ps1 +++ b/muranorepository/Services/scripts/SqlServerCluster/Failover-Cluster.ps1 @@ -1,239 +1,239 @@ -<# -.DESCRIPTION - -## Failover Cluster Input Data (from the UI) - -* Domain Membership - - [String] / [Select box] $DomainName - Domain name -* Domain User Credentials - - [String] $UserName - Username - - [Password string] $UserPassword - User password -* Shared Folder Information - - [String] $ShareServer - Server which will host the folder - - [String] $ShareName - Share name - - [String] $SharePath - Shared folder internal path -* Failover Cluster Members - - [String] $ClusterName - Cluster name - - [String] $ClusterIP - Static IP address that will be assigned to the cluster - - [String[]] $ClusterNodes - List of node names - - - -## Failover Cluster creation workflow - -* Create AD domain -* Join all the VMs to that domain -* Prepare nodes - - Install Failover Cluster prerequisites on all FC nodes -* Create failover cluster - - Create new cluster - - Add members -* Confugure FC quorum - - Create new folder that will be shared - - Share that folder with appropriate permissions - - Configure quorum mode - - - -## Helpful SmbShare* Functions - -* New-SmbShare -* Grant-SmbShareAccess - -#> - -trap { - &$TrapHandler -} - - - -function Install-FailoverClusterPrerequisites { - #Import-Module FailoverClusters - - #Add-WindowsFeature Failover-Clustering, RSAT-Clustering-PowerShell -} - - - -function New-FailoverClusterSharedFolder { - param ( - [String] $ClusterName, - [String] $DomainName, - [String] $ShareServer, - [String] $SharePath = $($Env:SystemDrive + '\FCShare'), - [String] $ShareName = 'FCShare', - [String] $UserName, - [String] $UserPassword, - $Credential = $null - ) - begin { - Show-InvocationInfo $MyInvocation - } - end { - Show-InvocationInfo $MyInvocation -End - } - process { - trap { - &$TrapHandler - } - - Write-Log "--> New-FailoverClusterSharedFolder" - - Write-Log "Creating shared folder for Failover Cluster ..." - - if ($Credential -eq $null) { - $Credential = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword" - } - - if ((Test-Connection -ComputerName $ShareServer -Count 1 -Quiet) -eq $false) { - throw("Server '$ShareServer' is unreachable via ICMP.") - } - - $Session = New-PSSession -ComputerName $ShareServer -Credential $Credential - - Write-Log "Creating folder on '$ShareServer' ..." - Invoke-Command -Session $Session -ScriptBlock { - param ( - [String] $SharePath, - [String] $ShareName, - [String] $ClusterAccount - ) - - Remove-SmbShare -Name $ShareName -Force -ErrorAction 'SilentlyContinue' - Remove-Item -Path $SharePath -Force -ErrorAction 'SilentlyContinue' - - New-Item -Path $SharePath -ItemType Container -Force - - New-SmbShare -Path $SharePath ` - -Name $ShareName ` - -FullAccess "$ClusterAccount", 'Everyone' ` - -Description "Shared folder for Failover Cluster." - - } -ArgumentList $SharePath, $ShareName, "$DomainName\$ClusterName`$" - - Write-Log "Confguring Failover Cluster to use shared folder as qourum resourse ..." - - $null = Set-ClusterQuorum -NodeAndFileShareMajority "\\$ShareServer\$ShareName" - - Write-Log "<-- New-FailoverClusterSharedFolder" - } -} - - - -function New-FailoverCluster { - param ( - [String] $ClusterName, - [String] $StaticAddress, - [String[]] $ClusterNodes, - [String] $DomainName, - [String] $UserName, - [String] $UserPassword, - $Credential - ) - begin { - Show-InvocationInfo $MyInvocation - } - end { - Show-InvocationInfo $MyInvocation -End - } - process { - trap { - &$TrapHandler - } - - Write-Log "ClusterNodes: $($ClusterNodes -join ', ')" - - if ($Credential -eq $null) { - $Credential = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword" - } - - foreach ($Node in $ClusterNodes) { - Write-LogDebug "Installing Failover Cluster modules on '$Node' ..." - $null = Invoke-Command ` - -ComputerName $Node ` - -Credential $Credential ` - -ScriptBlock { - Add-WindowsFeature Failover-Clustering, RSAT-Clustering-PowerShell - } - } - - Import-Module FailoverClusters - - if ((Get-Cluster $ClusterName -ErrorAction SilentlyContinue) -eq $null) { - Write-Log "Creating new cluster '$ClusterName' ..." -<# - Start-PowerShellProcess -Command @" -Import-Module FailoverClusters -New-Cluster -Name '$ClusterName' -StaticAddress '$StaticAddress' -"@ -Credential $Credential -NoBase64 -#> - New-Cluster -Name "$ClusterName" -StaticAddress "$StaticAddress" - Start-Sleep -Seconds 30 - } - else { - Write-Log "Cluster '$ClusterName' already exists." - } - - foreach ($Node in $ClusterNodes) { - Write-Log "Adding node '$Node' to the cluster '$ClusterName' ..." - if ((Get-ClusterNode $Node -ErrorAction SilentlyContinue) -eq $null) { - Write-Log "Adding node ..." -<# - Start-PowerShellProcess -Command @" -Import-Module FailoverClusters -Add-ClusterNode -Cluster '$ClusterName' -Name '$Node' -"@ -Credential $Credential -NoBase64 -#> - Add-ClusterNode -Cluster "$ClusterName" -Name "$Node" - } - else { - Write-Log "Node '$Node' already a part of the cluster '$ClusterName'." - } - } - } -} - - - -<# - -# Example - -$DomainName = 'fc-acme.local' -$DomainUser = 'Administrator' -$DomainPassword = 'P@ssw0rd' - -$ClusterName = 'fc-test' -$ClusterIP = '10.200.0.60' -$ClusterNodes = @('fc-node-01','fc-node-02','fc-node-03') - -$ShareServer = 'fc-dc-01' -$ShareName = 'FCShare' - -$SharePath = "C:\$ShareName" - - - -Import-Module CoreFunctions -Force - -$Creds = New-Credential ` - -UserName "$DomainName\$DomainUser" ` - -Password "$DomainPassword" - -New-FailoverCluster ` - -ClusterName $ClusterName ` - -StaticAddress $ClusterIP ` - -ClusterNodes $ClusterNodes ` - -Credential $Creds - -New-FailoverClusterSharedFolder ` - -ClusterName $ClusterName ` - -DomainName $DomainName ` - -ShareServer $ShareServer ` - -SharePath "$SharePath" ` - -ShareName "$ShareName" ` - -Credential $Creds - -#> +<# +.DESCRIPTION + +## Failover Cluster Input Data (from the UI) + +* Domain Membership + - [String] / [Select box] $DomainName - Domain name +* Domain User Credentials + - [String] $UserName - Username + - [Password string] $UserPassword - User password +* Shared Folder Information + - [String] $ShareServer - Server which will host the folder + - [String] $ShareName - Share name + - [String] $SharePath - Shared folder internal path +* Failover Cluster Members + - [String] $ClusterName - Cluster name + - [String] $ClusterIP - Static IP address that will be assigned to the cluster + - [String[]] $ClusterNodes - List of node names + + + +## Failover Cluster creation workflow + +* Create AD domain +* Join all the VMs to that domain +* Prepare nodes + - Install Failover Cluster prerequisites on all FC nodes +* Create failover cluster + - Create new cluster + - Add members +* Confugure FC quorum + - Create new folder that will be shared + - Share that folder with appropriate permissions + - Configure quorum mode + + + +## Helpful SmbShare* Functions + +* New-SmbShare +* Grant-SmbShareAccess + +#> + +trap { + &$TrapHandler +} + + + +function Install-FailoverClusterPrerequisites { + #Import-Module FailoverClusters + + #Add-WindowsFeature Failover-Clustering, RSAT-Clustering-PowerShell +} + + + +function New-FailoverClusterSharedFolder { + param ( + [String] $ClusterName, + [String] $DomainName, + [String] $ShareServer, + [String] $SharePath = $($Env:SystemDrive + '\FCShare'), + [String] $ShareName = 'FCShare', + [String] $UserName, + [String] $UserPassword, + $Credential = $null + ) + begin { + Show-InvocationInfo $MyInvocation + } + end { + Show-InvocationInfo $MyInvocation -End + } + process { + trap { + &$TrapHandler + } + + Write-Log "--> New-FailoverClusterSharedFolder" + + Write-Log "Creating shared folder for Failover Cluster ..." + + if ($Credential -eq $null) { + $Credential = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword" + } + + if ((Test-Connection -ComputerName $ShareServer -Count 1 -Quiet) -eq $false) { + throw("Server '$ShareServer' is unreachable via ICMP.") + } + + $Session = New-PSSession -ComputerName $ShareServer -Credential $Credential + + Write-Log "Creating folder on '$ShareServer' ..." + Invoke-Command -Session $Session -ScriptBlock { + param ( + [String] $SharePath, + [String] $ShareName, + [String] $ClusterAccount + ) + + Remove-SmbShare -Name $ShareName -Force -ErrorAction 'SilentlyContinue' + Remove-Item -Path $SharePath -Force -ErrorAction 'SilentlyContinue' + + New-Item -Path $SharePath -ItemType Container -Force + + New-SmbShare -Path $SharePath ` + -Name $ShareName ` + -FullAccess "$ClusterAccount", 'Everyone' ` + -Description "Shared folder for Failover Cluster." + + } -ArgumentList $SharePath, $ShareName, "$DomainName\$ClusterName`$" + + Write-Log "Confguring Failover Cluster to use shared folder as qourum resourse ..." + + $null = Set-ClusterQuorum -NodeAndFileShareMajority "\\$ShareServer\$ShareName" + + Write-Log "<-- New-FailoverClusterSharedFolder" + } +} + + + +function New-FailoverCluster { + param ( + [String] $ClusterName, + [String] $StaticAddress, + [String[]] $ClusterNodes, + [String] $DomainName, + [String] $UserName, + [String] $UserPassword, + $Credential + ) + begin { + Show-InvocationInfo $MyInvocation + } + end { + Show-InvocationInfo $MyInvocation -End + } + process { + trap { + &$TrapHandler + } + + Write-Log "ClusterNodes: $($ClusterNodes -join ', ')" + + if ($Credential -eq $null) { + $Credential = New-Credential -UserName "$DomainName\$UserName" -Password "$UserPassword" + } + + foreach ($Node in $ClusterNodes) { + Write-LogDebug "Installing Failover Cluster modules on '$Node' ..." + $null = Invoke-Command ` + -ComputerName $Node ` + -Credential $Credential ` + -ScriptBlock { + Add-WindowsFeature Failover-Clustering, RSAT-Clustering-PowerShell + } + } + + Import-Module FailoverClusters + + if ((Get-Cluster $ClusterName -ErrorAction SilentlyContinue) -eq $null) { + Write-Log "Creating new cluster '$ClusterName' ..." +<# + Start-PowerShellProcess -Command @" +Import-Module FailoverClusters +New-Cluster -Name '$ClusterName' -StaticAddress '$StaticAddress' +"@ -Credential $Credential -NoBase64 +#> + New-Cluster -Name "$ClusterName" -StaticAddress "$StaticAddress" + Start-Sleep -Seconds 30 + } + else { + Write-Log "Cluster '$ClusterName' already exists." + } + + foreach ($Node in $ClusterNodes) { + Write-Log "Adding node '$Node' to the cluster '$ClusterName' ..." + if ((Get-ClusterNode $Node -ErrorAction SilentlyContinue) -eq $null) { + Write-Log "Adding node ..." +<# + Start-PowerShellProcess -Command @" +Import-Module FailoverClusters +Add-ClusterNode -Cluster '$ClusterName' -Name '$Node' +"@ -Credential $Credential -NoBase64 +#> + Add-ClusterNode -Cluster "$ClusterName" -Name "$Node" + } + else { + Write-Log "Node '$Node' already a part of the cluster '$ClusterName'." + } + } + } +} + + + +<# + +# Example + +$DomainName = 'fc-acme.local' +$DomainUser = 'Administrator' +$DomainPassword = 'P@ssw0rd' + +$ClusterName = 'fc-test' +$ClusterIP = '10.200.0.60' +$ClusterNodes = @('fc-node-01','fc-node-02','fc-node-03') + +$ShareServer = 'fc-dc-01' +$ShareName = 'FCShare' + +$SharePath = "C:\$ShareName" + + + +Import-Module CoreFunctions -Force + +$Creds = New-Credential ` + -UserName "$DomainName\$DomainUser" ` + -Password "$DomainPassword" + +New-FailoverCluster ` + -ClusterName $ClusterName ` + -StaticAddress $ClusterIP ` + -ClusterNodes $ClusterNodes ` + -Credential $Creds + +New-FailoverClusterSharedFolder ` + -ClusterName $ClusterName ` + -DomainName $DomainName ` + -ShareServer $ShareServer ` + -SharePath "$SharePath" ` + -ShareName "$ShareName" ` + -Credential $Creds + +#> diff --git a/muranorepository/Services/scripts/SQLServerForAOAG.ps1 b/muranorepository/Services/scripts/SqlServerCluster/SQLServerForAOAG.ps1 similarity index 100% rename from muranorepository/Services/scripts/SQLServerForAOAG.ps1 rename to muranorepository/Services/scripts/SqlServerCluster/SQLServerForAOAG.ps1 diff --git a/muranorepository/Services/ui_forms/ActiveDirectory.yaml b/muranorepository/Services/ui_forms/ActiveDirectory.yaml index fabbfcf..4097d20 100644 --- a/muranorepository/Services/ui_forms/ActiveDirectory.yaml +++ b/muranorepository/Services/ui_forms/ActiveDirectory.yaml @@ -82,6 +82,16 @@ forms: type: password label: Recovery password attributeNames: false + - name: assignFloatingIP + required: false + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically to Primary DC + initial: false + required: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname template diff --git a/muranorepository/Services/ui_forms/AspNetApp.yaml b/muranorepository/Services/ui_forms/AspNetApp.yaml index b6ec4bf..7174c40 100644 --- a/muranorepository/Services/ui_forms/AspNetApp.yaml +++ b/muranorepository/Services/ui_forms/AspNetApp.yaml @@ -53,6 +53,16 @@ forms: errorMessages: invalid: Enter correct git repository url helpText: Enter a valid git repository URL + - name: assignFloatingIP + required: false + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically + initial: false + required: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname template diff --git a/muranorepository/Services/ui_forms/AspNetAppFarm.yaml b/muranorepository/Services/ui_forms/AspNetAppFarm.yaml index be12662..1448436 100644 --- a/muranorepository/Services/ui_forms/AspNetAppFarm.yaml +++ b/muranorepository/Services/ui_forms/AspNetAppFarm.yaml @@ -66,11 +66,6 @@ forms: maxValue: 100 initial: 2 helpText: Enter an integer value between 2 and 100 - - name: loadBalancerIp - type: clusterip - label: Load Balancer VIP - description: Specify IP number where Load Balancer will be running - helpText: Enter an free IP address from the subnet where instances will be created - name: loadBalancerPort type: integer label: Load Balancer port @@ -79,6 +74,15 @@ forms: initial: 80 description: Specify port number where Load Balancer will be running helpText: Enter an integer value from 1 to 65536 + - name: assignFloatingIP + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically + initial: false + required: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname template diff --git a/muranorepository/Services/ui_forms/LinuxApache.yaml b/muranorepository/Services/ui_forms/LinuxApache.yaml index 5265fd2..cdb8b87 100644 --- a/muranorepository/Services/ui_forms/LinuxApache.yaml +++ b/muranorepository/Services/ui_forms/LinuxApache.yaml @@ -27,6 +27,15 @@ forms: label: Instance Count description: Several instances with Apache web Service can be created at one time. helpText: Enter an integer value between 1 and 10 + - name: assignFloatingIP + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically + initial: false + required: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname diff --git a/muranorepository/Services/ui_forms/LinuxTelnet.yaml b/muranorepository/Services/ui_forms/LinuxTelnet.yaml index 4c9cf9b..2566baf 100644 --- a/muranorepository/Services/ui_forms/LinuxTelnet.yaml +++ b/muranorepository/Services/ui_forms/LinuxTelnet.yaml @@ -27,6 +27,15 @@ forms: hidden: true attributeNames: units initial: 1 + - name: assignFloatingIP + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically + initial: false + required: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname diff --git a/muranorepository/Services/ui_forms/MsSqlClusterServer.yaml b/muranorepository/Services/ui_forms/MsSqlClusterServer.yaml index 215b1bd..c0aee88 100644 --- a/muranorepository/Services/ui_forms/MsSqlClusterServer.yaml +++ b/muranorepository/Services/ui_forms/MsSqlClusterServer.yaml @@ -94,6 +94,10 @@ forms: type: clusterip label: Cluster Static IP description: Specify a valid IPv4 fixed IP. + # temporaryHack + widgetMedia: + js: [muranodashboard/js/support_placeholder.js] + css: {all: [muranodashboard/css/support_placeholder.css]} - name: clusterName type: string label: Cluster Name @@ -127,6 +131,10 @@ forms: errorMessages: invalid: Just letters, numbers, underscores and hyphens are allowed. description: User name that will be created to manage cluster instances. + # temporaryHack + widgetMedia: + js: [muranodashboard/js/support_placeholder.js] + css: {all: [muranodashboard/css/support_placeholder.css]} - name: sqlServicePassword type: password label: SQL User Password @@ -140,6 +148,15 @@ forms: attributeNames: false helpText: Enter an integer value between 2 and 5 description: Microsoft SQL Failover Cluster includes up to 5 instances. + - name: assignFloatingIP + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically + initial: false + required: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname template diff --git a/muranorepository/Services/ui_forms/MsSqlServer.yaml b/muranorepository/Services/ui_forms/MsSqlServer.yaml index 564be6f..ec51031 100644 --- a/muranorepository/Services/ui_forms/MsSqlServer.yaml +++ b/muranorepository/Services/ui_forms/MsSqlServer.yaml @@ -64,6 +64,15 @@ forms: description: Set system administrator password for the MS SQL Server. helpText: SQL server System Administrator account required: {YAQL: $.serviceConfiguration.mixedModeAuth} + - name: assignFloatingIP + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically + initial: false + required: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname template diff --git a/muranorepository/Services/ui_forms/WebServer.yaml b/muranorepository/Services/ui_forms/WebServer.yaml index 7205836..7655b46 100644 --- a/muranorepository/Services/ui_forms/WebServer.yaml +++ b/muranorepository/Services/ui_forms/WebServer.yaml @@ -44,6 +44,15 @@ forms: Service can be joined to the Active Directory domain. If you want to create an AD domain create the AD Service first. helpText: Optional field for a domain to which service can be joined + - name: assignFloatingIP + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically + initial: false + required: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname template diff --git a/muranorepository/Services/ui_forms/WebServerFarm.yaml b/muranorepository/Services/ui_forms/WebServerFarm.yaml index f711002..d3f1c81 100644 --- a/muranorepository/Services/ui_forms/WebServerFarm.yaml +++ b/muranorepository/Services/ui_forms/WebServerFarm.yaml @@ -54,11 +54,6 @@ forms: label: Instance Count description: Several instances with IIS Service can be created at one time. helpText: Enter an integer value between 2 and 100 - - name: loadBalancerIp - type: clusterip - label: Load Balancer VIP - description: Specify IP number where Load Balancer will be running - helpText: Enter an free IP address from the subnet where instances will be created - name: loadBalancerPort type: integer label: Load Balancer port @@ -67,6 +62,15 @@ forms: initial: 80 description: Specify port number where Load Balancer will be running helpText: Enter an integer value from 1 to 65536 + - name: assignFloatingIP + required: false + type: floatingip + label: Assign Floating IP + description: >- + Select to true to assign floating IP automatically + initial: false + widgetMedia: + css: {all: [muranodashboard/css/checkbox.css]} - name: unitNamingPattern type: string label: Hostname template diff --git a/muranorepository/Services/webServer-manifest.yaml b/muranorepository/Services/webServer-manifest.yaml index 3999a3a..f09412a 100644 --- a/muranorepository/Services/webServer-manifest.yaml +++ b/muranorepository/Services/webServer-manifest.yaml @@ -30,6 +30,7 @@ heat: - DefaultSecurity.template - WindowsSecurity.template - WebServerSecurity.template + - FloatingIP.template agent: - SetPassword.template diff --git a/muranorepository/Services/webServerFarm-manifest.yaml b/muranorepository/Services/webServerFarm-manifest.yaml index e9a8dd5..59aee3c 100644 --- a/muranorepository/Services/webServerFarm-manifest.yaml +++ b/muranorepository/Services/webServerFarm-manifest.yaml @@ -30,6 +30,7 @@ heat: - DefaultSecurity.template - WindowsSecurity.template - WebServerSecurity.template + - FloatingIPwithLB.template agent: - SetPassword.template diff --git a/muranorepository/Services/workflows/Apache.xml b/muranorepository/Services/workflows/Apache.xml index 2891c62..ac0fa83 100644 --- a/muranorepository/Services/workflows/Apache.xml +++ b/muranorepository/Services/workflows/Apache.xml @@ -1,8 +1,8 @@ - - + - insatalling Apache on unit ) + Installing Apache on unit ) diff --git a/muranorepository/Services/workflows/Common.xml b/muranorepository/Services/workflows/Common.xml index eff2205..0c861e7 100644 --- a/muranorepository/Services/workflows/Common.xml +++ b/muranorepository/Services/workflows/Common.xml @@ -22,4 +22,36 @@ - \ No newline at end of file + + + instance + + + + + + port- + + + + + + + ( diff --git a/muranorepository/Services/workflows/MsSqlCluster.xml b/muranorepository/Services/workflows/MsSqlCluster.xml index 2e3b86b..6002cdf 100644 --- a/muranorepository/Services/workflows/MsSqlCluster.xml +++ b/muranorepository/Services/workflows/MsSqlCluster.xml @@ -1,23 +1,25 @@ - - - - SQL-security - WindowsSecurity - - + + + + SQL-security + WindowsSecurity + WSFCSecurity + SQLClusterSecurity + + + desc="Units of SQL Server Cluster services which are part of the domain"> Creating instance ) @@ -26,7 +28,7 @@ + port- @@ -47,16 +49,16 @@ Instance ) created - - + + ( Applying address pair and opening SQL ports on ) @@ -73,30 +75,30 @@ Address pair and SQL ports are open on ) - - + + ( /$.services[?(@.type == 'activeDirectory' and @.domain == ' - + @@ -116,18 +118,18 @@ Unable to set admin password on unit ) due to - - + + + desc="Units of SQL Server Cluster services that are already joined AD domain"> - + - + - - ( + Failover cluster prerequisites installed on unit ) + - - + + ( @@ -174,7 +176,7 @@ @@ -201,23 +203,23 @@ - - ) - + + ) + - - + + due to - - + + - + + desc="First unit of SQL Server Cluster services that is already has failover cluster created"> - + @@ -234,23 +236,23 @@ - - ) configured - + + ) configured + - - + + ) due to - - + + - + + desc="All units of SQL Server Cluster services that is already has environment configured"> - + + + ( Unable to install SQL Server on unit ) due to - - + + - + + desc="All units of SQL Server Cluster services that has SQL Server installed"> - + - - AlwaysOn AG initialized for ) - + - - + + ( @@ -348,7 +350,7 @@ @@ -365,7 +367,7 @@ - + + + ( Unable to initialize primary replica for SQL Server AG for ) due to - - + + - + + desc="All units of SQL Server Cluster services that has primary replica initialized"> - + - - Secondary replica for SQL Server AG initialized for ) - + - - + + ( + + - :: + Assigning Floating IP to the to LB + + + + + + + + + -FloatingIPaddress + + + Unable to assign floating IP to