Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #! /bin/bash
- #==========================================================
- # Copyright @ 2014 Puppet Labs, LLC
- # Redistribution prohibited.
- # Address: 308 SW 2nd Ave., 5th Floor Portland, OR 97204
- # Phone: (877) 575-9775
- # Email: info@puppetlabs.com
- #
- # Please refer to the LICENSE.pdf file included
- # with the Puppet Enterprise distribution
- # for licensing information.
- #==========================================================
- #===[ Summary ]=========================================================
- # This program installs Puppet Enterprise. Run this file to start the
- # interactive installation or run with a "-h" option to display help.
- #===[ Conventions ]=====================================================
- # VARIABLES
- #
- # Variable names starting with "q_" are sanitized user answers to
- # questions asked by the `ask` function.
- #
- # Variable names starting with "t_" are transient variables for use
- # within a function. For example, "t_ask__name" is a transient variable
- # for storing a "name" within the "ask" function. This convention is
- # necessary because all POSIX sh variables are globals and there's no
- # way to localize the scope of variables to prevent functions from
- # stomping over each other's state.
- #
- # Variable names in all capital letters are globals that are
- # intentionally shared between different functions.
- #
- # This file can be sourced into a shell for use as a library.
- #===[ Global Varables ]================================================
- CONSOLE_PORT_OPTIONS="443,3000,3001,3002,3003,3004,3005"
- SLES_10_REGEX="sles-10-(i386|x86_64)"
- #===[ Functions ]=======================================================
- # Enqueue vendor packages based on user's answers...
- enqueue_vendor_packages() {
- # NONPORTABLE
- if [ "y" = "${q_puppet_cloud_install?}" -o "y" = "${q_database_install?}" ]; then
- case "${PLATFORM_NAME?}" in
- amazon | centos | rhel | sles)
- enqueue_package 'libxslt'
- ;;
- debian | ubuntu)
- enqueue_package 'libxslt1.1'
- ;;
- esac
- fi
- case "${PLATFORM_NAME?}" in
- amazon | centos | rhel)
- # pciutils are required for facter
- enqueue_package 'pciutils'
- # zlib is required for ruby
- enqueue_package 'zlib'
- enqueue_package 'which'
- enqueue_package 'libxml2'
- # dmidecode is required for facter, but not available on el4
- case "${PLATFORM_RELEASE}" in
- 6)
- enqueue_package 'dmidecode'
- enqueue_package 'cronie'
- ;;
- 5)
- enqueue_package 'dmidecode'
- enqueue_package 'vixie-cron'
- ;;
- esac
- enqueue_package 'net-tools'
- if [ y = "${q_puppetmaster_install?}" -o y = "${q_puppetdb_install?}" ]; then
- enqueue_package 'libjpeg'
- fi
- if [ y = "${q_puppetmaster_install?}" -o y = "${q_puppet_enterpriseconsole_install?}" ]; then
- enqueue_package 'curl'
- enqueue_package 'system-logos'
- # JJM mailcap is required for /etc/mime.types
- # In both RHEL x5 and x6
- enqueue_package 'mailcap'
- fi
- ;;
- sles)
- # pciutils and pmtools are required for facter
- if [ "${PLATFORM_RELEASE}" = "11" ] ; then
- enqueue_package 'pmtools'
- fi
- enqueue_package 'pciutils'
- enqueue_package 'cron'
- enqueue_package 'net-tools'
- enqueue_package 'libxml2'
- if [ y = "${q_puppetmaster_install?}" -o y = "${q_puppetdb_install?}" ]; then
- case "${PLATFORM_RELEASE}" in
- 11)
- enqueue_package 'libjpeg'
- ;;
- 12)
- enqueue_package 'libjpeg62'
- ;;
- esac
- fi
- if [ y = "${q_puppetmaster_install?}" -o y = "${q_puppet_enterpriseconsole_install?}" ]; then
- enqueue_package 'libapr1'
- enqueue_package 'curl'
- enqueue_package 'libapr-util1'
- fi
- ;;
- ubuntu | debian | cumulus)
- # pciutils and dmidecode are required for facter, except on powerpc which has no dmidecode
- enqueue_package 'pciutils'
- if [ "${PLATFORM_NAME?}" = "ubuntu" ] || [ "${PLATFORM_NAME?}" = "debian" ] ; then
- enqueue_package 'dmidecode'
- fi
- enqueue_package 'hostname'
- enqueue_package 'cron'
- enqueue_package 'libldap-2.4-2'
- enqueue_package 'libreadline5'
- enqueue_package 'libxml2'
- if [ y = "${q_puppetmaster_install?}" -o y = "${q_puppetdb_install?}" ]; then
- enqueue_package 'libjpeg62'
- fi
- if [ y = "${q_puppetmaster_install?}" -o y = "${q_puppet_enterpriseconsole_install?}" ]; then
- enqueue_package 'file'
- enqueue_package 'libmagic1'
- enqueue_package 'libpcre3'
- enqueue_package 'curl'
- enqueue_package 'perl'
- enqueue_package 'mime-support'
- enqueue_package 'libapr1'
- enqueue_package 'libcap2'
- enqueue_package 'libaprutil1'
- if [ "${PLATFORM_NAME?}" = "ubuntu" ] || [ "${PLATFORM_NAME?}" = "debian" ] ; then
- enqueue_package 'libaprutil1-dbd-sqlite3'
- enqueue_package 'libaprutil1-ldap'
- fi
- fi
- ;;
- solaris)
- if [ "${PLATFORM_RELEASE?}" = "11" ] ; then
- enqueue_package 'system/library/gcc-45-runtime'
- enqueue_package 'library/readline'
- enqueue_package 'library/security/openssl'
- fi
- # There are no vendor packages to install on Solaris 10
- ;;
- aix | eos)
- # No vendor packages
- :
- ;;
- *)
- display_failure "Do not know how to install vendor packages on this platform."
- ;;
- esac
- }
- # Install or upgrade all modules to /opt/puppet/share/puppet/modules
- #
- # Arguments: Whether it is an install or upgrade. Defaults to install
- install_puppet_modules() {
- # Save our current working directory.
- pushd "${INSTALLER_DIR}" &>/dev/null
- local t_install_dir="$(pwd)"
- t_module_target_dir="/opt/puppet/share/puppet/modules"
- t_module_backup_file="/opt/puppet/share/puppet/module.upgrade.backup.tar"
- if ! is_noop; then
- pushd ${t_module_target_dir} &>/dev/null
- if run_suppress_output "ls ${t_module_target_dir}/* &> /dev/null"; then
- # Backup current modules for recovery
- run_suppress_stdout "tar cf ${t_module_backup_file} ${t_module_target_dir}/*"
- # Check module whitelist
- if [ -f "${t_install_dir?}/modules/whitelist_modules.txt" ] ; then
- t_whitelist_modules=$( cat "${t_install_dir?}/modules/whitelist_modules.txt" )
- fi
- t_remove_modules=`ls "${t_module_target_dir}"`
- for t_whitelist_module in ${t_whitelist_modules} ;
- do
- t_remove_modules=`echo ${t_remove_modules?} | sed "s/\b${t_whitelist_module?}\b//"`
- done
- # Remove non-whitelist modules
- for t_remove_module in ${t_remove_modules?} ;
- do
- run_suppress_stdout "rm -rf ${t_remove_module?}"
- done
- fi
- for module_pkg in $( cat "${t_install_dir?}/modules/install_modules.txt" );
- do
- if [ -e "${t_install_dir?}/modules/${module_pkg}"* ]; then
- cur_mod_pkg=`ls "${t_install_dir?}/modules/${module_pkg?}"*`
- # Install module
- # --force is present to ensure we overwrite modules we control
- run_suppress_stdout '/opt/puppet/bin/puppet module install "'"${cur_mod_pkg}"'" --force --ignore-dependencies --modulepath /opt/puppet/share/puppet/modules'
- fi
- done
- # If there was a puppet-module symlink in ${PLATFORM_SYMLINK_TARGET}, remove it
- run_suppress_output "rm -f ${PLATFORM_SYMLINK_TARGET}/puppet-module"
- # Pop back to $INSTALLER_DIR
- popd &>/dev/null
- fi
- # Pop back to original $PWD
- popd &>/dev/null
- run_suppress_stdout "chown ${PLATFORM_PUPPET_USER}:${PLATFORM_PUPPET_GROUP} -R ${t_module_target_dir?}"
- }
- # Copy puppet modules to /opt/puppet/share/installer/modules and make sure they
- # are readable to the world so that they can be served by a puppet fileserver
- # mount to compile masters. This will remove any existing modules in the
- # directory on upgrades.
- create_module_mount() {
- run_suppress_stdout "rm -rf /opt/puppet/share/installer/modules"
- run_suppress_stdout "cp -R ${INSTALLER_DIR?}/modules /opt/puppet/share/installer/modules"
- run_suppress_stdout "chmod 0755 /opt/puppet/share/installer/modules"
- }
- configure_postgresql_server() {
- # For fresh installs in which case we're installing postgres, make shmmax
- # big enough. For upgrades from 3.x, presumably everything is already
- # working so we'll just leave it alone.
- if ! is_upgrade; then
- t_postgres_memory_mb="$(/opt/puppet/bin/facter memorysize_mb)"
- t_postgres_shmmax_req="$((${t_postgres_memory_mb%.*} * 1024 * 1024 / 2))"
- t_postgres_shmmax_avail="$(/sbin/sysctl kernel.shmmax | awk '{ printf $3 }')"
- # Set kernel.shmmax if it's less than half the available memory size
- if [ "${t_postgres_shmmax_req?}" -gt ${t_postgres_shmmax_avail?} ]; then
- export t_manage_kernel_shmmax='y'
- fi
- fi
- apply_template_manifest "postgresql_server.pp.erb"
- }
- configure_puppetdb() {
- display "Configuring puppetdb..."
- create_package_repo
- # Uses
- # t_puppetdb_java_args
- apply_template_manifest "puppetdb.pp.erb"
- remove_package_repo
- display "PuppetDB configured."
- }
- # Setup a package repo on the master for the platform we're currently installing on
- setup_package_repo() {
- display_comment "Setting up package repository for ${PLATFORM_TAG}"
- # The pe_repo module wants to make a symlink to an extracted tarball, so we
- # have to mimic the structure of an extracted tarball.
- t_pe_repo_basename="puppet-enterprise-${PE_VERSION?}-${PLATFORM_TAG?}"
- t_pe_repo_package_dir="/opt/puppet/packages/public/${t_pe_repo_basename?}/packages"
- run "mkdir -p '${t_pe_repo_package_dir?}'"
- run "cp -R '$(platform_package_dir)' '${t_pe_repo_package_dir?}'"
- # now mimic an extracted agent tarball, except have it symlink to the packages dir
- # created above
- t_pe_repo_agent_basename="${t_pe_repo_basename?}-agent"
- t_pe_repo_agent_package_dir="/opt/puppet/packages/public/${t_pe_repo_agent_basename?}/agent_packages"
- run "mkdir -p '${t_pe_repo_agent_package_dir?}'"
- # To prevent us from duplicating agent packages on the system, symlink the agent_packages dir to
- # to the main packages dir for this platform.
- # If this link already exists that means we're trying to rerun the installer
- # on a failed upgrade so throw some -f at `ln` so that `ln` doesn't complain it already exists.
- run "ln -fs '${t_pe_repo_package_dir?}/${PLATFORM_TAG?}' '${t_pe_repo_agent_package_dir?}/${PLATFORM_TAG?}'"
- # Apply the pe_repo class to generate the install bash scripts.
- # Template uses:
- # - t_pe_repo_puppet_class
- # - q_tarball_server
- export t_pe_repo_puppet_class="$(platform_puppet_class)"
- apply_template_manifest "pe_repo.pp.erb"
- }
- # Simple listing of cloud gems that get enqueued
- # on many platforms (EL5, EL6, SLES11, lucid, squeeze, precise, wheezy)
- #
- handle_cloud() {
- enqueue_package 'pe-cloud-provisioner'
- enqueue_package 'pe-cloud-provisioner-libs'
- # This is now being enqueued for all el, sles, deb and ubuntu installs so is no longer needed here.
- # enqueue_package 'pe-rubygem-net-ssh'
- }
- # Enqueue installer environment
- enqueue_installer_packages() {
- case "${PLATFORM_NAME?}" in
- amazon | centos | rhel)
- # zlib is required for ruby
- enqueue_package 'zlib'
- ;;
- esac
- enqueue_package 'pe-ruby'
- enqueue_package 'pe-bundler'
- enqueue_package 'pe-installer'
- }
- enqueue_agent_packages() {
- case "${PLATFORM_NAME?}" in
- amazon | centos | rhel | sles | ubuntu | debian | cumulus | eos)
- t_el_4_regex="el-4-(i386|x86_64)"
- if [[ $PLATFORM_TAG =~ ${t_el_4_regex?} ]] || [[ $PLATFORM_TAG =~ ${SLES_10_REGEX?} ]] || [ "${PLATFORM_TAG}" = "eos-4-i386" ]; then
- enqueue_package 'pe-puppet-enterprise-release'
- enqueue_package 'pe-libyaml'
- enqueue_package 'pe-virt-what'
- enqueue_package 'pe-ruby'
- enqueue_package 'pe-ruby-shadow'
- enqueue_package 'pe-ruby-stomp'
- enqueue_package 'pe-mcollective-common'
- enqueue_package 'pe-mcollective'
- enqueue_package 'pe-facter'
- enqueue_package 'pe-puppet'
- enqueue_package 'pe-augeas'
- enqueue_package 'pe-ruby-augeas'
- enqueue_package 'pe-hiera'
- enqueue_package 'pe-ruby-rgen'
- enqueue_package 'pe-rubygem-deep-merge'
- enqueue_package 'pe-openssl'
- else
- enqueue_package 'pe-agent'
- fi
- # pe-ruby-ldap and pe-rubygem-net-ssh are not built for agent only installs
- if [ "false" = "${CLIENT_ONLY?}" ]; then
- enqueue_package 'pe-ruby-ldap'
- enqueue_package 'pe-rubygem-net-ssh'
- fi
- ;;
- aix)
- enqueue_package 'pe-puppet-enterprise-release'
- enqueue_package 'pe-augeas'
- enqueue_package 'pe-libyaml'
- enqueue_package 'pe-openssl'
- enqueue_package 'pe-ruby'
- enqueue_package 'pe-ruby-augeas'
- enqueue_package 'pe-ruby-stomp'
- enqueue_package 'pe-ruby-rgen'
- enqueue_package 'pe-rubygem-deep-merge'
- enqueue_package 'pe-hiera'
- enqueue_package 'pe-facter'
- enqueue_package 'pe-mcollective'
- enqueue_package 'pe-mcollective-common'
- enqueue_package 'pe-puppet'
- ;;
- solaris)
- case "${PLATFORM_RELEASE?}" in
- 10)
- enqueue_package 'PUPpuppet-enterprise-release'
- enqueue_package 'PUPlibyaml'
- enqueue_package 'PUPruby'
- enqueue_package 'PUPopenssl'
- enqueue_package 'PUPstomp'
- enqueue_package 'PUPmcollective'
- enqueue_package 'PUPfacter'
- enqueue_package 'PUPpuppet'
- enqueue_package 'PUPhiera'
- enqueue_package 'PUPruby-augeas'
- enqueue_package 'PUPaugeas'
- enqueue_package 'PUPruby-rgen'
- enqueue_package 'PUPdeep-merge'
- ;;
- 11)
- enqueue_package 'pe-puppet-enterprise-release'
- enqueue_package 'pe-augeas'
- enqueue_package 'pe-libyaml'
- enqueue_package 'pe-ruby'
- enqueue_package 'pe-ruby-shadow'
- enqueue_package 'pe-ruby-augeas'
- enqueue_package 'pe-stomp'
- enqueue_package 'pe-ruby-rgen'
- enqueue_package 'pe-deep-merge'
- enqueue_package 'pe-hiera'
- enqueue_package 'pe-facter'
- enqueue_package 'pe-mcollective'
- enqueue_package 'pe-puppet'
- ;;
- *)
- display_failure "Do not know how to install on Solaris ${PLATFORM_RELEASE}"
- ;;
- esac
- ;;
- *)
- display_failure "Do not know how to install Ruby or Puppet on this platform"
- ;;
- esac
- }
- query_about_master_connectivity() {
- t_qamc__msg="Puppet Master at '${q_puppetagent_server}:8140' could not be reached."
- # fail if the answer file tells us to
- if [ 'y' == "${q_fail_on_unsuccessful_master_lookup}" ]; then
- display_failure "${t_qamc__msg} Aborting installation as directed by answer file. Set 'q_fail_on_unsuccessful_master_lookup' to 'n' if installation should continue despite communication failures."
- elif [ 'n' == "${q_fail_on_unsuccessful_master_lookup}" -a 'y' == "${IS_ANSWER_REQUIRED}" ]; then
- break
- fi
- ask q_continue_or_reenter_master_hostname "The installer couldn’t reach the puppet master server at ${q_puppetagent_server}. If this server name is correct, please check your DNS configuration to ensure the puppet master node can be reached by name, and make sure your firewall settings allow traffic on port 8140. Enter ‘r’ if you need to re-enter the puppet master’s name; otherwise, enter ‘c’ to continue." cr
- if [ 'c' == "${q_continue_or_reenter_master_hostname}" ]; then
- break
- else
- unset q_puppetagent_server
- ask q_puppetagent_server "Puppet master hostname to connect to?" String 'puppet'
- fi
- unset q_continue_or_reenter_master_hostname
- }
- cron_enable() {
- case "${PLATFORM_NAME?}" in
- amazon | centos | rhel | eos )
- enable_service 'crond'
- bounce_service 'crond'
- ;;
- debian | ubuntu | sles | cumulus)
- enable_service 'cron'
- bounce_service 'cron'
- ;;
- solaris)
- run_suppress_stdout "/usr/sbin/svcadm enable svc:/system/cron:default"
- ;;
- aix)
- if ! /usr/sbin/lsitab "cron" > /dev/null; then
- run_suppress_stdout '/usr/sbin/mkitab "cron:23456789:respawn:/usr/sbin/cron"'
- fi
- ;;
- esac
- }
- # Utility function to re-query the user regarding an unavailable
- # value for a database variable, e.g. a db name that is in use already
- # Ask twice, then fail.
- # Arguments:
- # 1. The value of the resource to check for
- # 2. A string, one of either "user" or "db" to flag *which* kind of resource to check
- # 3. The variable that the value should be assigned to
- # 4. An optional message string to display to the user in the ask message
- # 5. An optional failure message to display
- requery_db_resource_value() {
- t_success="n"
- t_count=0
- t_value="${1?}"
- t_type="${2?}"
- t_variable="${3?}"
- t_message="${4}"
- t_fail_message="${5}"
- while [ "n" = "${t_success}" ] && [ ${t_count} -lt 2 ] ; do
- unset "${t_variable}"
- if [ -z "${t_message}" ] ; then
- ask ${t_variable} "The ${t_type} name (${t_value}) for this host already exists on the PostgreSQL server. Please enter an unused ${t_type} name?" String
- else
- ask ${t_variable} "${t_message}" String
- fi
- eval t_value="${!t_variable}"
- if is_db_name_available "${t_value}" "${t_type}" ; then
- t_success="y"
- fi
- t_count=$(($t_count + 1))
- done
- if [ "n" = "${t_success}" ] ; then
- # We tried twice, and failed. Fail hard.
- if [ -z "${t_fail_message}" ] ; then
- display_failure "Unable to create the ${t_type} with the name ${t_value}, ${t_type} already exists on the PostgreSQL server."
- else
- display_failure "${t_fail_message}"
- fi
- fi
- }
- # Wait for the database server to be up and running. This is used so that we
- # don't try to verify the database until the server is ready to accept
- # connections. This is only done on database installs. $1 is the number of
- # connection attempts to make. Returns 0 if the database is running, and 1 if
- # the maximum number of attempts is reached.
- wait_for_db() {
- t_wait_for_db_max_retries="${1?}"
- t_wait_for_db_tries=0
- while [ "${t_wait_for_db_tries?}" -lt "${t_wait_for_db_max_retries?}" ]; do
- if eval "su - ${q_database_root_user} -c \"${t_path_to_psql?} --command='\l'\" -s /bin/bash" &> /dev/null; then
- return 0
- else
- sleep 0.5
- t_wait_for_db_tries=$(expr "${t_wait_for_db_tries?}" + 1)
- fi
- done
- return 1
- }
- # Wait for a service to be up and running.
- # This is only done on all-in-one installs.
- # $1 is the url to attempt the connection.
- # $2 is the number of connection attempts to make.
- # Returns 0 if the database is running, and 1 if
- # the maximum number of attempts is reached.
- wait_for_service() {
- t_wait_for_service_max_retries="${2?}"
- t_wait_for_service_tries=0
- t_wait_for_service_url="${1?}"
- while [ "${t_wait_for_service_tries?}" -lt "${t_wait_for_service_max_retries?}" ]; do
- run_suppress_stdout "curl --tlsv1 -s ${t_wait_for_service_url}"
- t_contact_service_exit_status=$?
- # These are both known SSL failures which mean the service is up and listening.
- # Since we're not using any known certs, we expect to be able to connect and then have an SSL failure.
- # 35 SSL connect error. The SSL handshaking failed.
- # 60 Peer certificate cannot be authenticated with known CA certificates.
- case $t_contact_service_exit_status in
- 35 | 60)
- return 0
- ;;
- *)
- sleep 1
- t_wait_for_service_tries=$(expr "${t_wait_for_service_tries?}" + 1)
- ;;
- esac
- done
- return 1
- }
- # Wait for Node Classifier to be up and running.
- # This is only done on all-in-one installs.
- # $1 is the url to attempt the connection.
- # $2 is the number of connection attempts to make.
- # Returns 0 if the database is running, and 1 if
- # the maximum number of attempts is reached.
- wait_for_nc() {
- t_wait_for_service_max_retries="${2?}"
- t_wait_for_service_tries=0
- t_wait_for_service_url="${1?}"
- while [ "${t_wait_for_service_tries?}" -lt "${t_wait_for_service_max_retries?}" ]; do
- # We grep for that specific string because when that endpoint returns an actual
- # date for last updated, we can be sure that the Node Classifier will have classes available
- # If last update is null, that means there are no classes in the NC.
- if run_suppress_stdout "curl --tlsv1 -s --cacert /etc/puppetlabs/puppet/ssl/certs/ca.pem --key /opt/puppet/share/puppet-dashboard/certs/${q_puppetagent_certname}.private_key.pem --cert /opt/puppet/share/puppet-dashboard/certs/${q_puppetagent_certname}.cert.pem ${t_wait_for_service_url}/v1/last-class-update | grep -q last_update.*[[:digit:]]"; then
- return 0
- else
- sleep 3
- t_wait_for_service_tries=$(expr "${t_wait_for_service_tries?}" + 1)
- fi
- done
- return 1
- }
- # Verify a single database on the database server.
- # The arguments to this function are the database, username, and password to
- # verify.
- verify_single_database() {
- t_verify_database="${1?}"
- t_verify_user="${2?}"
- t_verify_password="${3?}"
- create_db_encoding="ENCODING 'utf8' LC_CTYPE 'en_US.utf8' LC_COLLATE 'en_US.utf8' template template0"
- t_psql_remote_string="--host='${q_database_host?}' --port=${q_database_port?}"
- t_db_setup=0
- if ! output=$(run "PGPASSWORD='${t_verify_password?}' ${t_path_to_psql?} --username='${t_verify_user?}' ${t_psql_remote_string} --dbname='${t_verify_database?}' --command='\dT' 2>&1"); then
- if echo $output | $PLATFORM_EGREP -q "role \"${t_verify_user?}\" does not exist" ; then
- echo "Could not connect to the postgresql server using the user: ${t_verify_user?}. Please log in as a privileged user and set it up manually. Example SQL commands:" | display_wrapped_text
- display_newline
- printf -- '%s' "
- CREATE USER \"${t_verify_user}\" PASSWORD '${t_verify_password?}';
- "
- elif echo $output | $PLATFORM_EGREP -q "database \"${t_verify_database?}\" does not exist" ; then
- echo "Could not connect to postgresql server using database: ${t_verify_database?} with user: ${t_verify_user?}. Please log in as a privileged user and set it up manually. Example SQL commands:" | display_wrapped_text
- display_newline
- printf -- '%s' "
- CREATE DATABASE \"${t_verify_database}\" OWNER \"${t_verify_user}\" ${create_db_encoding?};
- "
- else
- echo "Could not connect to postgres server using the user: ${t_verify_user?} and database: ${t_verify_database?}. Please log in as a privileged user and set up the user or database manually. Example SQL commands:" | display_wrapped_text
- display_newline
- printf -- '%s' "
- CREATE USER \"${t_verify_user}\" PASSWORD '${t_verify_password?}';
- CREATE DATABASE \"${t_verify_database}\" OWNER \"${t_verify_user}\" ${create_db_encoding?};
- "
- fi
- display_newline
- t_db_setup=1
- else
- display_comment "Database ${t_verify_database} verified successfully."
- fi
- }
- # verify_postgresql: there are two basic cases
- # 1) we are verifying a root user
- # 2) we are verifying existing credentials and databases
- #
- # The first and only argument represents which databases to verify: console,
- # puppetdb, classifier, activity, rbac, or some comma delimited subset thereof.
- #
- # The function uses several installer variables including:
- # - q_database_install
- # - q_database_host
- # - q_database_port
- # - q_database_root_user
- # - q_puppet_enterpriseconsole_database_name
- # - q_puppet_enterpriseconsole_database_user
- # - q_puppet_enterpriseconsole_database_password
- # - q_puppetdb_database_name
- # - q_puppetdb_database_user
- # - q_puppetdb_database_password
- # - q_activity_database_name
- # - q_activity_database_user
- # - q_activity_database_password
- # - q_classifier_database_name
- # - q_classifier_database_user
- # - q_classifier_database_password
- # - q_rbac_database_name
- # - q_rbac_database_user
- # - q_rbac_database_password
- # - t_path_to_psql
- #
- # It returns 0 for success if the databases/users exist or the root account is valid
- # and non-zero for failure if those databases/users don't exist or the root account is invalid
- verify_postgresql() {
- t_db_setup=0
- # If we are doing the setup, we need to verify that the root account credentials are good.
- if [ y = "${q_database_install?}" ]; then
- if ! eval "su - ${q_database_root_user} -c \"${t_path_to_psql?} --command='\l'\" -s /bin/bash" &> /dev/null; then
- display_failure "Could not connect to the postgresql server using the ${q_database_root_user} user."
- fi
- else
- t_psql_remote_string="--host='${q_database_host?}' --port=${q_database_port?}"
- # If we aren't doing the setup, we need to verify that the console and PuppetDB account credentials are good and the databases exist.
- # We check each in turn and give example SQL commands for each block upon failure. We don't fail hard on error until the function returns,
- # so all five blocks can display errors to the user.
- # First we check that the console user exists and that we can connect to the console database using the console user credentials.
- if [ "${1?}" != "${1/console,/match/}" ]; then
- if ! verify_single_database "${q_puppet_enterpriseconsole_database_name?}" "${q_puppet_enterpriseconsole_database_user?}" "${q_puppet_enterpriseconsole_database_password?}"; then
- t_db_setup=1
- fi
- fi
- if [ "${1?}" != "${1/puppetdb,/match}" ]; then
- if ! verify_single_database "${q_puppetdb_database_name?}" "${q_puppetdb_database_user?}" "${q_puppetdb_database_password?}"; then
- t_db_setup=1
- fi
- # Verify pg_trgm extension is created (PE-6859)
- if output=$(run "PGPASSWORD='${q_puppetdb_database_password?}' ${t_path_to_psql?} --username='${q_puppetdb_database_user?}' ${t_psql_remote_string} --dbname='${q_puppetdb_database_name?}' --command='\dx pg_trgm' 2>&1"); then
- if echo "${output?}" | grep -q "pg_trgm.*|" ; then
- display_comment "Database ${q_puppetdb_database_name} pg_trgm extension verified."
- else
- display_error "Database ${q_puppetdb_database_name} pg_trgm extension could not be found. Please install pg_trgm."
- t_db_setup=1
- fi
- fi
- fi
- if [ "${1?}" != "${1/activity,/match}" ]; then
- if ! verify_single_database "${q_activity_database_name?}" "${q_activity_database_user?}" "${q_activity_database_password?}"; then
- t_db_setup=1
- fi
- fi
- if [ "${1?}" != "${1/classifier,/match}" ]; then
- if ! verify_single_database "${q_classifier_database_name?}" "${q_classifier_database_user?}" "${q_classifier_database_password?}"; then
- t_db_setup=1
- fi
- fi
- if [ "${1?}" != "${1/rbac,/match}" ]; then
- if ! verify_single_database "${q_rbac_database_name?}" "${q_rbac_database_user?}" "${q_rbac_database_password?}"; then
- t_db_setup=1
- fi
- # Verify citext extension is created (PE-6859)
- if output=$(run "PGPASSWORD='${q_rbac_database_password?}' ${t_path_to_psql?} --username='${q_rbac_database_user?}' ${t_psql_remote_string} --dbname='${q_rbac_database_name?}' --command='\dx citext' 2>&1"); then
- if echo "${output?}" | grep -q "citext.*|" ; then
- display_comment "Database ${q_rbac_database_name} citext extension verified."
- else
- display_error "Database ${q_rbac_database_name} citext extension could not be found. Please install citext."
- t_db_setup=1
- fi
- fi
- fi
- fi
- return ${t_db_setup?}
- }
- # Verify the db credentials, as well as the console db if we're installing the
- # console.
- verify_db() {
- t_verify_dbs=''
- display_comment "Verifying postgresql credentials..."
- if ! is_upgrade && [ y = "${q_puppetdb_install?}" ]; then
- t_verify_dbs='puppetdb,'
- fi
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- # If upgrading, we should only verify the new databases for 3.7 because
- # we can assume the existing console/puppetdb is working.
- if is_upgrade && [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ]; then
- t_verify_dbs="${t_verify_dbs} rbac, classifier, activity,"
- elif ! is_upgrade; then
- t_verify_dbs="${t_verify_dbs} console, rbac, classifier, activity,"
- fi
- fi
- if ! verify_postgresql "${t_verify_dbs?}"; then
- display_failure "The provided postgresql instance could not be verified. Please follow the above instructions and try again."
- fi
- }
- # Warn about needed open ports
- warn_open_ports() {
- t_inbound_port_string=""
- t_outbound_port_string=""
- # Add 443 for HTTPS connections if the console is being installed...
- # Also 4433 for HTTPS connections if the classifier is being installed...
- # Also 4435 for HTTPS connections if the dashboard is being installed...
- # ... inbound if it's a console install...
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- t_inbound_port_string="${t_inbound_port_string?}${q_puppet_enterpriseconsole_httpd_port?}, 4433, 4435, "
- elif [ y = "${q_puppetmaster_install?}" ]; then
- t_outbound_port_string="${t_outbound_port_string?}4433, 4435, "
- fi
- # Add 8140 for the puppetmaster and 61613 for mcollective/stomp/activemq...
- # ... inbound if it's a master install...
- if [ y = "${q_puppetmaster_install?}" ]; then
- t_inbound_port_string="${t_inbound_port_string?}8140, 61613, "
- else
- # ... otherwise outbound
- t_outbound_port_string="${t_outbound_port_string?}8140, 61613, "
- fi
- # Add 5432 for Postgres...
- # ... inbound if it's a non-console database install...
- if [ y = "${q_database_install?}" -a ! y = "${q_puppet_enterpriseconsole_install?}" ]; then
- t_inbound_port_string="${t_inbound_port_string?}${q_database_port?}, "
- fi
- # ... outbound on a non-database PuppetDB or console install
- if [ ! y = "${q_database_install?}" ] && [ y = "${q_puppetdb_install}" -o y = "${q_puppet_enterpriseconsole_install}" ]; then
- t_outbound_port_string="${t_outbound_port_string?}${q_database_port?}, "
- fi
- # Add 8081 for PuppetDB if not a standalone install...
- if [ ! y = "${q_all_in_one_install?}" ]; then
- # ... inbound if it's a PuppetDB install
- if [ y = "${q_puppetdb_install?}" ]; then
- t_inbound_port_string="${t_inbound_port_string?}${q_puppetdb_port?}, "
- fi
- # ... outbound if it's a puppetmaster or console install
- if [ y = "${q_puppetmaster_install}" ]; then
- t_outbound_port_string="${t_outbound_port_string?}${q_puppetdb_port?}, "
- fi
- fi
- if [ -n "${t_inbound_port_string?}" ]; then
- echo "If you have a firewall running, please ensure the following TCP ports are open: ${t_inbound_port_string%, }" | display_wrapped_text
- display_newline
- fi
- if [ -n "${t_outbound_port_string?}" ]; then
- echo "If you have a firewall running, please ensure outbound connections are allowed to the following TCP ports: ${t_outbound_port_string%, }" | display_wrapped_text
- display_newline
- fi
- }
- #===[ Main ]============================================================
- . "$(dirname "${0?}")/utilities"
- # Version variables to use when creating links and printing messages.
- PE_VERSION=$(cat "$(dirname "${0?}")/VERSION" 2> /dev/null)
- PE_LINK_VER=$(echo ${PE_VERSION?} | cut -d '.' -f1,2)
- if [ "puppet-enterprise-installer" = "$(basename "${0?}")" ]; then
- #---[ Environment ]-----------------------------------------------------
- # Installing via sudo may not add required path components
- PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
- #---[ Paranoia ]--------------------------------------------------------
- # Exit immediately if a simple command exits with a non-zero status:
- set -e
- #---[ Prepare ]---------------------------------------------------------
- # Catch CTRL-C and "set -e" errors:
- register_exception_handler
- # Setup "PLATFORM_*" variables:
- prepare_platform
- #---[ Process command-line options ]------------------------------------
- ANSWER_FILE_TO_LOAD=
- ANSWER_FILE_TO_SAVE=
- IS_ANSWER_REQUIRED=n
- LOGFILE=
- IS_NOOP=n
- IS_DEBUG=n
- IS_VERBOSE_DEBUG=n
- IS_SAVE_ANSWERS=n
- IS_SUPPRESS_OUTPUT=n
- export IS_UPGRADE=n
- while getopts a:A:Dhl:nqs:V name; do
- case "$name" in
- a)
- ANSWER_FILE_TO_LOAD="${OPTARG?}"
- IS_ANSWER_REQUIRED=y
- ;;
- A)
- ANSWER_FILE_TO_LOAD="${OPTARG?}"
- IS_ANSWER_REQUIRED=n
- ;;
- D)
- IS_DEBUG=y
- ;;
- h)
- display_header
- display_usage
- ;;
- l)
- LOGFILE="${OPTARG?}"
- ;;
- n)
- IS_NOOP=y
- ;;
- q)
- IS_SUPPRESS_OUTPUT=y
- ;;
- s)
- ANSWER_FILE_TO_SAVE="${OPTARG?}"
- IS_SAVE_ANSWERS=y
- ;;
- V)
- IS_VERBOSE_DEBUG=y
- ;;
- ?)
- display_header
- display_usage "Illegal option specified"
- ;;
- esac
- done
- #---[ Announce installation ]-------------------------------------------
- # Enforce quiet mode if specified
- if is_quiet ; then
- run_quiet_mode
- fi
- # Enforce very verbose debugging if specified
- is_verbose_debug
- # Announce installer:
- display_header
- # Set umask to 0022. This is in a subshell and inside a conditional, so this umask will only
- # persist for the run of the installer.
- umask 0022
- # Prepare the installer variable:
- installer_dir > /dev/null
- [ -s $(installer_dir)/VERSION ] || display_failure "The VERSION file seems to be missing from your installer. The installer cannot proceed without it."
- # Check if we are on a supported platform
- if [ ${IS_SAVE_ANSWERS} != y ]; then
- platform_support_check
- fi
- # Check user:
- prepare_user
- # Load answers if specified:
- if [ ! -z "${ANSWER_FILE_TO_LOAD?}" ]; then
- load_answers "${ANSWER_FILE_TO_LOAD?}"
- # Backward compatibility with answers from PE <= 1.2.x
- convert_answers
- fi
- # Prepare log file:
- if ( ! is_save_answers ) && ( ! is_noop ) ; then
- prepare_log_file "install"
- fi
- # PE-537 without libgcc_s.so.1, our compiled software will not run.
- solaris_re='solaris-10-(i386|sparc)'
- if [[ "${PLATFORM_TAG}" =~ $solaris_re ]] && ( ! is_package_installed "SUNWgccruntime" ); then
- display_failure "SUNWgccruntime provides /usr/sfw/lib/libgcc_s.so.1, which is required for Puppet Enterprise, please install the package from your Solaris installation media and run ${0} again."
- fi
- # Check if we are working on a system that already has an install
- if ( ! is_save_answers ) && [ -x /opt/puppet/bin/puppet ]; then
- export IS_UPGRADE=y
- CURRENT_PE_BUILD=$(/opt/puppet/bin/puppet --version | cut -d' ' -f4 | cut -d')' -f1)
- CURRENT_PE_VERSION=${CURRENT_PE_BUILD%%-*}
- export CURRENT_PE_MAJOR=$(echo $CURRENT_PE_VERSION | cut -d'.' -f1)
- export CURRENT_PE_MINOR=$(echo $CURRENT_PE_VERSION | cut -d'.' -f2)
- CURRENT_PE_INCR=$(echo $CURRENT_PE_VERSION | cut -d'.' -f3)
- if [ "${CURRENT_PE_BUILD?}" = "${PE_VERSION?}" ]; then
- display_newline
- display " === Puppet-Enterprise version ${CURRENT_PE_BUILD?} already installed === "
- display_newline
- quit
- else
- display_newline
- display " === Upgrade from version ${CURRENT_PE_BUILD?} detected === "
- display_newline
- fi
- # Fail if the current installed version is less than PE 3.3.2
- t_el_4_regex="el-4-(i386|x86_64)"
- if ([[ ! "$PLATFORM_TAG" =~ ${t_el_4_regex?} ]] && [ "$(echo_vercmp 3.3.2 $CURRENT_PE_VERSION)" = "1" ]); then
- display_failure "In order to upgrade to ${PE_VERSION}, you must be running PE 3.3.2 or higher. However, for the best upgrade experience, we recommend upgrading from the latest 3.3.x release (http://puppetlabs.com/misc/pe-files/previous-releases). Once you have upgraded to 3.3.x, you can complete the upgrade to ${PE_VERSION}. For more information, see http://docs.puppetlabs.com/pe/3.7/install_upgrading.html."
- elif ([[ "$PLATFORM_TAG" =~ ${t_el_4_regex?} ]] && [ "$(echo_vercmp 2.0.3 $CURRENT_PE_VERSION)" = "1" ]); then
- display_failure "In order to upgrade to ${PE_VERSION} on EL4, you must first be running PE 2.0.3. To complete the upgrade to ${PE_VERSION}, you need to download and install the 2.0.3 release (http://puppetlabs.com/misc/pe-files/previous-releases). For more information, see http://docs.puppetlabs.com/pe/2.0/install_upgrading.html. Once you have updated to 2.0.3, you can complete the upgrade to ${PE_VERSION}."
- fi
- # Check if this is an Enterprise Readiness Guide deployment (as opposed
- # to a stock install). If so, bail out because we can't automatically
- # upgrade.
- if [ -e "/etc/puppetlabs/installer/details.txt" ]; then
- display_failure "Your current version of Puppet Enterprise cannot be automatically upgraded because it uses a non-standard deployment and/or configuration. Please contact Puppet Labs support for assistance with your upgrade."
- fi
- q_puppetagent_install=y
- q_puppetagent_certname="$(/opt/puppet/bin/puppet agent --configprint certname)"
- q_puppetagent_server="$(/opt/puppet/bin/puppet agent --configprint server)"
- if is_cloud_provisioner; then
- q_puppet_cloud_install='y'
- else
- q_puppet_cloud_install='n'
- fi
- if is_puppetmaster; then
- q_puppetmaster_install='y'
- q_puppetmaster_certname="$(/opt/puppet/bin/puppet master --configprint certname)"
- t_puppetmaster_node_terminus="$(get_ini_field '/etc/puppetlabs/puppet/puppet.conf' 'node_terminus')"
- t_puppetmaster_external_node="$(get_ini_field '/etc/puppetlabs/puppet/puppet.conf' 'external_nodes')"
- export t_puppetserver_java_args="$(get_java_args "pe-puppetserver")"
- if [ "${t_puppetmaster_node_terminus}" == '' -o "${t_puppetmaster_node_terminus}" == 'console' -o "${t_puppetmaster_node_terminus}" == 'classifier' ] || [ "${t_puppetmaster_node_terminus}" == 'exec' -a "${t_puppetmaster_external_node}" == '/etc/puppetlabs/puppet-dashboard/external_node' ]; then
- q_puppetmaster_external_node_terminus=${q_puppetmaster_external_node_terminus:-"n"}
- fi
- #q_puppetca_install='y'
- extract_console_location_from_enc_script
- else
- q_puppetmaster_install='n'
- #q_puppetca_install='n'
- fi
- if is_console; then
- q_puppet_enterpriseconsole_install='y'
- # In 3.7, puppetproxy.conf has the web port for the console and
- # puppetdashboard.conf has dashboard-specific vhosts. Prior to 3.7,
- # there was only puppetdashboard.conf and it held the web port.
- if [ -f '/etc/puppetlabs/httpd/conf.d/puppetproxy.conf' ]; then
- t_console_httpd_port_file='/etc/puppetlabs/httpd/conf.d/puppetproxy.conf'
- else
- t_console_httpd_port_file='/etc/puppetlabs/httpd/conf.d/puppetdashboard.conf'
- fi
- q_puppet_enterpriseconsole_httpd_port="${q_puppet_enterpriseconsole_httpd_port:-"$(${PLATFORM_EGREP} Listen ${t_console_httpd_port_file?} | sed -e 's/^\s*Listen [^:]*:\([[:digit:]]*\)\s*$/\1/')"}"
- if ! [[ "${q_puppet_enterpriseconsole_httpd_port?}" =~ ^[0-9]+$ ]]; then
- display_failure "Invalid console port '${q_puppet_enterpriseconsole_httpd_port?}': please make sure ${t_console_httpd_port_file?} does not contain extra vhost entries."
- fi
- # We transfer by default, but the user can override with an answer file.
- if [ "${CURRENT_PE_MAJOR?}" -eq "2" ]; then
- : ${q_database_transfer:='y'}
- else
- q_database_transfer='n'
- fi
- export t_console_services_java_args="$(get_java_args "pe-console-services")"
- q_puppet_enterpriseconsole_database_name=${q_puppet_enterpriseconsole_database_name:-"$(/opt/puppet/bin/ruby -ryaml -e "print YAML.load_file('/etc/puppetlabs/puppet-dashboard/database.yml')['common']['database']")"}
- q_puppet_enterpriseconsole_database_user=${q_puppet_enterpriseconsole_database_user:-"$(/opt/puppet/bin/ruby -ryaml -e "print YAML.load_file('/etc/puppetlabs/puppet-dashboard/database.yml')['common']['username']")"}
- q_puppet_enterpriseconsole_database_password=${q_puppet_enterpriseconsole_database_password:-"$(/opt/puppet/bin/ruby -ryaml -e "print YAML.load_file('/etc/puppetlabs/puppet-dashboard/database.yml')['common']['password']")"}
- q_database_host=${q_database_host:-"$(/opt/puppet/bin/ruby -ryaml -e "print YAML.load_file('/etc/puppetlabs/puppet-dashboard/database.yml')['common']['host']")"}
- q_database_port=${q_database_port:-"$(/opt/puppet/bin/ruby -ryaml -e "print YAML.load_file('/etc/puppetlabs/puppet-dashboard/database.yml')['common']['port']")"}
- if [ -z "${q_puppet_enterpriseconsole_httpd_port}" ]; then
- display_failure "Could not determine the existing Puppet Enterprise console port"
- fi
- else
- q_puppet_enterpriseconsole_install='n'
- fi
- if is_puppetdb; then
- q_puppetdb_install='y'
- # If it's not installed, we have to ask if they want to move to
- # pe-postgres, so we can't just set this to no.
- if is_postgres; then
- q_database_install='y'
- fi
- q_puppetdb_plaintext_port="${q_puppetdb_plaintext_port:-"$(get_ini_field '/etc/puppetlabs/puppetdb/conf.d/jetty.ini' 'port')"}"
- q_puppetdb_hostname="${q_puppetdb_hostname:-$q_puppetagent_certname}"
- q_puppetdb_port="${q_puppetdb_port:-"$(get_ini_field '/etc/puppetlabs/puppetdb/conf.d/jetty.ini' 'ssl-port')"}"
- export t_puppetdb_java_args="$(get_java_args "pe-puppetdb")"
- t_main_database_subname="$(get_ini_field '/etc/puppetlabs/puppetdb/conf.d/database.ini' 'subname')"
- q_database_host="${q_database_host:-$(echo "${t_main_database_subname?}" | sed -e 's/\/\/\([^:][^:]*\):\([0-9][0-9]*\)\/\(\S*\)/\1/')}"
- q_database_port="${q_database_port:-$(echo "${t_main_database_subname?}" | sed -e 's/\/\/\([^:][^:]*\):\([0-9][0-9]*\)\/\(\S*\)/\2/')}"
- q_puppetdb_database_name="${q_puppetdb_database_name:-$(echo "${t_main_database_subname?}" | sed -e 's/\/\/\([^:][^:]*\):\([0-9][0-9]*\)\/\(\S*\)/\3/')}"
- q_puppetdb_database_user="${q_puppetdb_database_user:-$(get_ini_field '/etc/puppetlabs/puppetdb/conf.d/database.ini' 'username')}"
- q_puppetdb_database_password="${q_puppetdb_database_password:-$(get_ini_field '/etc/puppetlabs/puppetdb/conf.d/database.ini' 'password')}"
- else
- # This could be changed later during the all-in-one check.
- q_puppetdb_install='n'
- if is_puppetmaster; then
- # Try to figure out where PuppetDB is from the puppetdb.conf file
- if is_package_installed 'pe-puppetdb-terminus' && [ -e '/etc/puppetlabs/puppet/puppetdb.conf' ]; then
- q_puppetdb_hostname=${q_puppetdb_hostname:-"$(get_ini_field '/etc/puppetlabs/puppet/puppetdb.conf' server)"}
- q_puppetdb_port=${q_puppetdb_port:-"$(get_ini_field '/etc/puppetlabs/puppet/puppetdb.conf' port)"}
- fi
- elif is_console; then
- # Try to figure out where PuppetDB is from the answers.install
- # file (if the user hasn't removed it). Although it is not an
- # INI file, it has the same field=value format, so the
- # `get_ini_field` helper function should be able to parse it
- # correctly.
- if [ -s '/etc/puppetlabs/installer/answers.install' ]; then
- q_puppetdb_hostname=${q_puppetdb_hostname:-"$(get_ini_field '/etc/puppetlabs/installer/answers.install' q_puppetdb_hostname)"}
- q_puppetdb_port=${q_puppetdb_port:-"$(get_ini_field '/etc/puppetlabs/installer/answers.install' q_puppetdb_port)"}
- fi
- fi
- fi
- if is_postgres; then
- q_database_shared_buffers="$(get_postgres_setting "shared_buffers")"
- q_database_maintenance_work_mem="$(get_postgres_setting 'maintenance_work_mem')"
- q_database_effective_cache_size="$(get_postgres_setting 'effective_cache_size')"
- q_database_wal_buffers="$(get_postgres_setting 'wal_buffers')"
- q_database_work_mem="$(get_postgres_setting 'work_mem')"
- q_database_checkpoint_segments="$(get_postgres_setting 'checkpoint_segments')"
- q_database_log_min_duration_statement="$(get_postgres_setting 'log_min_duration_statement')"
- fi
- # If we're a master and a console, we must be either a 2.x install (in
- # which case we get converted to all-in-one), or a 3.x all-in-one
- # install (which means we must already have puppetdb and the database).
- if is_puppetmaster && is_console; then
- q_all_in_one_install='y'
- q_puppetdb_install='y'
- else
- q_all_in_one_install='n'
- fi
- if is_console; then
- if [ "$(echo_vercmp 3.2.0 $CURRENT_PE_VERSION)" = "1" ] && [ "${CURRENT_PE_MAJOR?}" -eq "3" ]; then
- display_comment "Collecting information..."
- #If the current version is 3.x but less than 3.2.0 we'll be upgrading the database IDs within PostgreSQL from int to bigint.
- #We try to analyze as much as we can depending on the PE configuration
- t_current_largest_table_size=$(verbose_bundle_exec "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:console:current_largest_table_size RAILS_ENV=production" | tail -n 1)
- t_extra_space_percent=20
- #with 'set -e' the let command would fail if it returned zero...
- if [ ${t_current_largest_table_size?} -gt 0 ]; then
- let t_required_tablespace_free="${t_current_largest_table_size?}*(100+${t_extra_space_percent?})/100"
- else
- t_required_tablespace_free=1
- fi
- # q_database_install may not be set here in the case where it's
- # not a database install (because we plan to ask later), so the
- # answer is optional. But if it *is* a database, we know for
- # sure, so it's safe.
- if [ ! ${t_current_largest_table_size?} = "-1" ] && [ y = "${q_database_install}" ]; then
- #This is the best case - we are on pe-postgres running on the local machine
- t_current_tablespace_free=$(verbose_bundle_exec "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:console:current_tablespace_free RAILS_ENV=production" | tail -n 1)
- if [ ! ${t_current_tablespace_free?} = "-1" ]; then
- #This should always get here (free space should be known) unless there's something unexpected
- if [ ${t_current_tablespace_free?} -lt ${t_required_tablespace_free?} ]; then
- #We know that there is not enough space so we warn the user. We may be wrong though
- #if the database has not been vacuumed regularly! User still has the chance to take the risk.
- ask q_upgrade_with_low_disk_space "This upgrade requires an update to your database. To complete successfully, this database update temporarily requires at least ${t_required_tablespace_free?}MB of free disk space on the node providing the database role. Only ${t_current_tablespace_free?}MB of disk space appears to be available, so this upgrade may fail if you choose to continue! Continue anyway?" yN
- if [ ! y = "${q_upgrade_with_low_disk_space?}" ]; then
- quit 1
- fi
- fi
- fi
- else
- #The database is not local or it is not pe-postgres - we can't compute the free tablespace
- t_current_tablespace_free="-1"
- fi
- if [ ${t_current_tablespace_free?} = "-1" ]; then
- if [ ! ${t_current_largest_table_size?} = "-1" ]; then
- #Since we are on pe-postgres we known how much free space we need but we can't compute how much we really have
- ask q_upgrade_with_unknown_disk_space "This upgrade requires an update to your database. To complete successfully, this database update temporarily requires at least ${t_required_tablespace_free?}MB of free disk space on the node providing the database role. Is there at least ${t_required_tablespace_free?}MB of free disk space available?" yn
- else
- #Since we are not on pe-postgres we don't known how much free space we need, it's all user's reponsibility
- ask q_upgrade_with_unknown_disk_space "This upgrade requires an update to your database. To complete successfully, this database update temporarily requires some free disk space on the node providing the database role. The space required is about ${t_extra_space_percent?}% larger than the size of the largest table currently in your database. Is this amount of free disk space available?" yn
- fi
- if [ ! y = "${q_upgrade_with_unknown_disk_space?}" ]; then
- quit 1
- fi
- fi
- fi
- fi
- # If we're a master or console, we need to make sure to respect that
- # the user may have opted out of update checking. If they set it in an
- # answer file *now*, use that. Otherwise check if they set it in the
- # old answer file (if it's still around). Otherwise it's on by default.
- if (is_puppetmaster || is_console) && [ -s '/etc/puppetlabs/installer/answers.install' ]; then
- q_pe_check_for_updates=${q_pe_check_for_updates:-"$(get_ini_field '/etc/puppetlabs/installer/answers.install' q_pe_check_for_updates)"}
- fi
- if (is_puppetdb || is_console) && [ -s '/etc/puppetlabs/installer/answers.install' ]; then
- q_puppetmaster_certname="${q_puppetmaster_certname:-"$(get_ini_field '/etc/puppetlabs/installer/answers.install' 'q_puppetmaster_certname')"}"
- fi
- fi
- #---[ Support for installing in a symlinked opt dir ]--------------------
- if [ -L "/opt" ]; then
- case "${PLATFORM_NAME?}" in
- solaris)
- declare -x PKG_NONABI_SYMLINKS='true'
- ;;
- esac
- fi
- if ! is_upgrade && [ 'false' = "${CLIENT_ONLY?}" ]; then
- #---[ Interview user ]--------------------------------------------------
- if [ -z "${ANSWER_FILE_TO_LOAD?}" ]; then
- t_automated_install_doc_link="http://docs.puppetlabs.com/pe/${PE_LINK_VER?}/install_automated.html"
- t_answer_file_ref_doc_link="http://docs.puppetlabs.com/pe/${PE_LINK_VER?}/install_answer_file_reference.html"
- display_step 'GUIDED INSTALLATION' n
- display_newline
- display "Before you begin, choose an installation method. We've provided a few paths to choose from."
- display_newline
- echo "- Perform a guided installation using the web-based interface. Think of this as an installation interview in which we ask you exactly how you want to install PE. In order to use the web-based installer, you must be able to access this machine on port 3000 and provide the SSH credentials of a user with root access. This method will login to servers on your behalf, install Puppet Enterprise and get you up and running fairly quickly." | display_wrapped_text 0 0
- display_newline
- display_newline
- echo "- Use the web-based interface to create an answer file so that you login to the servers yourself and perform the installation locally. Refer to Answer File Installation (${t_automated_install_doc_link?}), which provides an overview on installing PE with an answer file." | display_wrapped_text 0 0
- display_newline
- display_newline
- echo "- If you choose not to use the web-based interface, you can write your own answer file or use the answer file(s) provided in the PE installation tarball. Check the Answer File Reference Overview (${t_answer_file_ref_doc_link?}) to get started." | display_wrapped_text 0 0
- display_newline
- display_newline
- ask q_packages_install "Install packages and perform a guided install?" Yn
- if [ 'y' = "${q_packages_install?}" ]; then
- display_newline
- display "Installing setup packages."
- display_newline
- enqueue_installer_packages
- run_suppress_stdout install_queued_packages
- # Copy the pe installer
- t_installer_dest="/opt/puppet/share/installer/installer"
- run "mkdir -p '${t_installer_dest?}'"
- run "cp -pR '$(installer_dir)'/* '${t_installer_dest?}'"
- # Start installer service
- INSTALLER_SUPPORTED_PORTS="3000,4567"
- INSTALLER_PORT=$(find_unused_tcp_port "${PLATFORM_HOSTNAME}" "${INSTALLER_SUPPORTED_PORTS}")
- if [ "${INSTALLER_PORT}" != '' ]; then
- echo "Please go to https://${PLATFORM_HOSTNAME}:${INSTALLER_PORT} in your browser to continue installation. Be sure to use https:// and that port ${INSTALLER_PORT?} is reachable through the firewall." | display_wrapped_text 0 0
- display_newline
- # This will block
- pushd /opt/puppet/share/installer &>/dev/null
- run_suppress_output "RACK_ENV=production /opt/puppet/bin/bundle exec thin start --debug -p ${INSTALLER_PORT} -a 0.0.0.0 --ssl --ssl-disable-verify"
- popd &>/dev/null
- display_newline
- display "Your infrastructure has finished installing."
- display "Thank you for installing Puppet Enterprise!"
- quit 0
- else
- display_failure "Could not open a TCP port for web server. Tried ${INSTALLER_SUPPORTED_PORTS}."
- fi
- else
- display_newline
- display_major_separator
- display_newline
- display "!! Installation cancelled"
- display_newline
- display_major_separator
- quit 1
- fi
- fi
- fi
- display_step 'SELECT AND CONFIGURE ROLES' n
- display_newline
- if [ 'false' = "${CLIENT_ONLY?}" ]; then
- echo "This installer lets you select and install the various roles required in a Puppet Enterprise deployment: puppet master, console, database, cloud provisioner, and puppet agent." | display_wrapped_text
- display_newline
- display_newline
- display "NOTE: when specifying hostnames during installation, use the fully-qualified domain name (foo.example.com) rather than a shortened name (foo)."
- display_newline
- display_product 'puppet master' "The puppet master serves configurations to a group of puppet agent nodes. This role also provides MCollective's message queue and client interface. It should be installed on a robust, dedicated server."
- ask q_puppetmaster_install 'Install puppet master?' yN
- if [ y = "${q_puppetmaster_install?}" ]; then
- display_product "standalone install" "You may choose to either install PuppetDB and the console on this node, or to install each service on its own node. If you choose not to install PuppetDB and the console on this node, you will be asked where to find them."
- ask q_all_in_one_install "Install PuppetDB and console on this node?" Yn
- # If all-in-one, then autoselect everything. If not all-in-one,
- # then deselect everything.
- if [ y = "${q_all_in_one_install?}" ]; then
- q_puppetdb_install='y'
- q_puppet_enterpriseconsole_install='y'
- else
- q_puppetdb_install='n'
- q_puppet_enterpriseconsole_install='n'
- fi
- else
- q_all_in_one_install=n
- ask q_puppetagent_server "Puppet master hostname to connect to?" String puppet
- if ( ! is_save_answers ) && [ 'n' = "${q_skip_master_verification:-"n"}" ] ; then
- while ! tcp_port_in_use "${q_puppetagent_server}" 8140 ; do
- query_about_master_connectivity
- done
- fi
- : ${q_fail_on_unsuccessful_master_lookup:='y'}
- : ${q_puppetca_hostname:=${q_puppetagent_server?}}
- fi
- # If you're *not* installing a master, you can choose PuppetDB
- if [ ! y = "${q_puppetmaster_install?}" ]; then
- display_product 'database support' "This role provides database support for PuppetDB and PE's console. PuppetDB is a centralized data service that caches data generated by Puppet and provides access to it via a robust API. The console uses data provided by a PostgreSQL server and database both of which will be installed along with PuppetDB on the node you specify."
- echo "IMPORTANT: If you choose not to install PuppetDB at this time, you will be prompted for the host name of the node you intend to use to provide database services. Note that you must install database support on that node for the console to function. When using a separate node, you should install database support on it BEFORE installing the console role." | display_wrapped_text
- display_newline
- display_newline
- ask q_puppetdb_install 'Install PuppetDB?' yN
- # If you've chosen PuppetDB, you cannot choose console
- if [ y = "${q_puppetdb_install?}" ]; then
- q_puppet_enterpriseconsole_install='n'
- fi
- fi
- if [ 'y' = "${q_puppetdb_install?}" ]; then
- : ${q_puppetdb_plaintext_port:='8080'}
- : ${q_puppetdb_port:='8081'}
- if ( ! is_save_answers ) && ( ! is_upgrade ); then
- # Verify that ports 8080 and 8081 (or the port from the answer file) are available if this isn't answer-save mode.
- for port in $q_puppetdb_plaintext_port $q_puppetdb_port; do
- if tcp_port_in_use "127.0.0.1" $port ; then
- display_newline
- display_failure "Port $port appears to be in use. This port is required for PuppetDB. Please either move the services for this port to another or install on a system with this port available."
- fi
- done
- fi
- fi
- # If you're not installing master or PuppetDB, you can install console
- if [ ! y = "${q_puppetmaster_install?}" -a ! y = "${q_puppetdb_install?}" ]; then
- display_product 'console' "The console is a web interface where you can view reports, classify nodes, control Puppet runs, and invoke MCollective agents. It can be installed on the puppet master's node, but for performance considerations, especially in larger deployments, it can also be installed on a separate node."
- ask q_puppet_enterpriseconsole_install 'Install the console?' yN
- q_puppetca_install='n'
- fi
- # Verify that port 8140 is available if this isn't answer-save mode and we're not upgrading.
- if ( ! is_save_answers ) && ( ! is_upgrade ) && [ 'y' = "${q_puppetmaster_install?}" -o 'y' = "${q_puppet_enterpriseconsole_install?}" ] && tcp_port_in_use "127.0.0.1" 8140 ; then
- display_newline
- display_failure "Port 8140 appears to be in use. This port is required for the puppet master. Please either move the services for this port to another or install on a system with this port available."
- fi
- # Verify they haven't somehow chosen two out of three roles (such as
- # answer file). This shouldn't actually be possible, since we
- # automatically deselect roles during the interview, but better to be
- # safe than sorry.
- if [ y = "${q_puppetmaster_install?}" -a y = "${q_puppetdb_install?}" -a ! y = "${q_puppet_enterpriseconsole_install?}" ]; then
- display_failure "You may not select the Puppet master and PuppetDB roles together without the console role. Please select either an all-in-one install or a single role."
- fi
- if [ y = "${q_puppetmaster_install?}" -a ! y = "${q_puppetdb_install?}" -a y = "${q_puppet_enterpriseconsole_install?}" ]; then
- display_failure "You may not select the Puppet master and console roles together without the PuppetDB role. Please select either an all-in-one install or a single role."
- fi
- if [ ! y = "${q_puppetmaster_install?}" -a y = "${q_puppetdb_install?}" -a y = "${q_puppet_enterpriseconsole_install?}" ]; then
- display_failure "You may not select the PuppetDB and console roles together without the Puppet master role. Please select either an all-in-one install or a single role."
- fi
- # If we're not installing PuppetDB, we probably need to know where it is.
- if [ ! y = "${q_puppetdb_install?}" ] && [ y = "${q_puppetmaster_install?}" -o y = "${q_puppet_enterpriseconsole_install?}" ]; then
- if [ y = "${q_puppetmaster_install?}" ] && ! is_upgrade; then
- display_newline
- echo "Puppet Enterprise requires the installation of PuppetDB. PuppetDB needs to be cleanly installed on a new node after the installation of the puppet master has successfully completed. Please provide the hostname and port for the node on which you will be installing PuppetDB." | display_wrapped_text
- display_newline
- display_newline
- fi
- ask q_puppetdb_hostname "Hostname for contacting PuppetDB?" String
- ask q_puppetdb_port "Port for contacting PuppetDB?" Port "8081"
- : ${q_puppetdb_plaintext_port:='8080'}
- fi
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- : ${q_puppetmaster_enterpriseconsole_hostname:='127.0.0.1'}
- elif [ y = "${q_puppetmaster_install?}" ]; then
- if ! is_upgrade ; then
- display_newline
- echo "Puppet Enterprise requires the installation of the Console. The Console needs to be cleanly installed on a new node after the installation of the puppet master has successfully completed. Please provide the hostname and port for the node on which you will be installing the Console." | display_wrapped_text
- display_newline
- display_newline
- fi
- ask q_puppetmaster_enterpriseconsole_hostname "Hostname for contacting the console?" String
- : ${q_puppetmaster_enterpriseconsole_certname:="${q_puppetmaster_enterpriseconsole_hostname?}"}
- fi
- display_product 'cloud provisioner' 'The cloud provisioner can create and bootstrap new machine instances and add them to your Puppet infrastructure. It should be installed on a trusted node where site administrators have shell access.'
- ask q_puppet_cloud_install 'Install the cloud provisioner?' yN
- if [ y = "${q_puppetmaster_install?}" -o y = "${q_puppet_enterpriseconsole_install?}" -o y = "${q_puppetdb_install?}" -o y = "${q_puppet_cloud_install?}" ]; then
- q_puppetagent_install='y'
- display_product 'puppet agent' 'The puppet agent role is automatically installed with the console, puppet master, puppetdb, and cloud provisioner roles.'
- else
- display_product 'puppet agent' 'The puppet agent applies configurations from the puppet master and submits reports and inventory information. It should be installed on every node you plan to manage with Puppet.'
- ask q_puppetagent_install 'Install puppet agent?' Yn
- fi
- if [ y = "${q_puppetmaster_install?}" ]; then
- ask q_puppetmaster_certname "The puppet master's certificate will contain a unique name (\"certname\"); this should be the main DNS name at which it can be reliably reached. Puppet master's certname?" StringForceLowerCase "${PLATFORM_HOSTNAME?}" # The master's certname gets used as the filebucket server in site.pp. If it isn't a reachable DNS name, users have to edit site.pp post-install.
- # We only use alt names when generating the master's cert, so we
- # don't need them for upgrade
- if ! is_upgrade; then
- ask q_puppetmaster_dnsaltnames "The puppet master's certificate can contain DNS aliases; agent nodes will only trust the master if they reach it at its certname or one of these official aliases. Puppet master's DNS aliases (comma-separated list)?" StringDNSName "$(display_dnsaltnames "${q_puppetmaster_certname?}" "puppet")"
- fi
- display_newline
- : ${q_puppetca_hostname:=${q_puppetmaster_certname?}}
- fi
- if [ y = "${q_puppetdb_install?}" -o y = "${q_puppet_enterpriseconsole_install?}" ]; then
- if [ y = "${q_puppetdb_install?}" ]; then
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- t_main_database_products="The Puppet Enterprise console and PuppetDB"
- t_main_database_verb="require"
- else
- t_main_database_products="PuppetDB"
- t_main_database_verb="requires"
- fi
- echo "${t_main_database_products?} ${t_main_database_verb?} a PostgreSQL database and a user account able to edit it. Puppet Enterprise includes a Postgresql server which you can install locally, or you can specify an existing remote database (which must be configured and available prior to installing the console or PuppetDB)." | display_wrapped_text
- elif [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- echo "The Puppet Enterprise console requires a PostgreSQL database and a user account able to edit it. This database and the Puppet Enterprise PostgreSQL server are automatically installed and configured, along with PuppetDB, on a node you select for the database support role. You should install this role BEFORE installing the console role. After installing the database support role, you can find auto-generated passwords for the database user and the authentication database user in '/etc/puppetlabs/installer/database_info.install' on that node." | display_wrapped_text
- fi
- display_newline
- display_newline
- fi
- if [ y = "${q_puppetdb_install?}" ]; then
- ask q_database_install "Install the included Puppet Enterprise PostgreSQL server locally?" Yn
- # This variable represents whether or not we're using PE postgres,
- # independently of whether it's installed on this node. The main
- # purpose of the variable is to feed into the console install so we
- # know whether to classify the PuppetDB node with manage_database
- # true or false.
- q_pe_database="${q_database_install?}"
- else
- q_database_install='n'
- fi
- if [ y = "${q_database_install?}" ]; then
- if ! is_save_answers && ! is_upgrade && [ -x /opt/puppet/var/lib/pgsql ] && [ "y" != "${q_skip_backup}" ]; then
- display_newline
- display " === Existing Puppet Enterprise data detected === "
- display_newline
- display_comment "It looks like Puppet Enterprise had been installed on this machine and it was uninstalled without the purge data option (-d). The existing databases cannot be reused by this installer. You can either quit this installation or the installer can move your existing database directory to /opt/puppet/var/lib/pgsql.<yyyymmddHHMMSS>.bak and create a new one."
- ask q_backup_and_purge_old_database_directory "Would you like to backup your existing database directory and continue installing Puppet Enterprise?" yN
- if [ "y" != "${q_backup_and_purge_old_database_directory?}" ]; then
- quit 1
- fi
- else
- q_backup_and_purge_old_database_directory='n'
- fi
- q_database_root_user="pe-postgres"
- : ${q_database_host:="${PLATFORM_HOSTNAME?}"}
- q_database_port='5432'
- # Verify that port 5432 is available for the pe-postgresql server
- if ( ! is_save_answers ) && ( ! is_upgrade ) && tcp_port_in_use "127.0.0.1" ${q_database_port} ; then
- display_newline
- display_failure "Port ${q_database_port} appears to be in use. This port is required for the Puppet Enterprise Postgresql Server. Please either move the services for this port to another or install on a system with this port available."
- fi
- q_database_root_password="${q_database_root_password:-"$(gen_password)"}"
- # We're doing setup, so set db variable defaults
- set_database_defaults
- elif [ y = "${q_puppetdb_install?}" -o y = "${q_puppet_enterpriseconsole_install?}" ] && ! is_upgrade; then
- # On split PuppetDB/Console installs, default to PuppetDB location
- # as the likely location of postgres. It's either that or they're
- # using their own. On combined or PuppetDB-only installs, we have
- # nothing to reasonably default to.
- if [ y = "${q_puppet_enterpriseconsole_install?}" -a ! y = "${q_puppetdb_install?}" ]; then
- ask q_database_host "What is the hostname of the PostgreSQL server?" String "${q_puppetdb_hostname?}"
- else
- ask q_database_host "What is the hostname of the PostgreSQL server?" String
- fi
- ask q_database_port "What is the port of the PostgreSQL server?" Port "5432"
- if [ y = "${q_puppet_enterpriseconsole_install?}" -a ! y = "${q_database_install?}" ]; then
- ask q_pe_database "Was the PostgreSQL server installed and configured by Puppet Enterprise?" yN
- fi
- if [ y = "${q_puppetdb_install?}" ]; then
- ask q_puppetdb_database_name "What is the name of the PuppetDB database?" String pe-puppetdb
- ask q_puppetdb_database_user "What is the name of the PuppetDB database user?" String pe-puppetdb
- ask q_puppetdb_database_password "What is the password for ${q_puppetdb_database_user?} (the database user)?" Password4
- fi
- fi
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- if ! is_upgrade; then
- # We already know the port to use in an upgrade, so we don't want to find a new one or ask.
- if ! is_save_answers; then
- default_console_port=$(find_unused_tcp_port "127.0.0.1" "${CONSOLE_PORT_OPTIONS}")
- if [ -z "${default_console_port}" ] ; then
- ask q_puppet_enterpriseconsole_httpd_port "None of the default ports (${CONSOLE_PORT_OPTIONS}) are open for use by the PE console. What is a port for use by the PE console?" Port
- else
- q_puppet_enterpriseconsole_httpd_port="${q_puppet_enterpriseconsole_httpd_port:-"${default_console_port}"}"
- fi
- else
- ask q_puppet_enterpriseconsole_httpd_port "What is a port for use by the PE console?" Port "443"
- fi
- fi
- if [ y = "${q_puppetmaster_install}" ]; then
- : ${q_puppet_enterpriseconsole_master_hostname:="${q_puppetmaster_certname?}"}
- fi
- set_t_path_to_psql
- if ! is_upgrade && [ ! y = "${q_database_install?}" ]; then
- ask q_puppet_enterpriseconsole_database_name "What is the name of the console database?" String console
- ask q_puppet_enterpriseconsole_database_user "What is the name of the console database user?" String console
- ask q_puppet_enterpriseconsole_database_password "What is the password for ${q_puppet_enterpriseconsole_database_user?} (the database user)?" Password4
- fi
- if is_upgrade && [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- display_newline
- echo '!!! WARNING: Existing Puppet Enterprise Console users will not be migrated. Please set a new password for your superuser.' | display_wrapped_text 0
- display_newline
- display_newline
- fi
- if ! is_upgrade || [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- ask q_puppet_enterpriseconsole_auth_password "Password for Puppet Enterprise Console superuser 'admin' (minimum 8 characters)?" Password8
- if [ ! y = "${q_database_install?}" ]; then
- ask q_rbac_database_name "What is the name of the RBAC database?" String pe-rbac
- ask q_rbac_database_user "What is the name of the RBAC database user?" String pe-rbac
- ask q_rbac_database_password "What is the password for ${q_rbac_database_user?} (the database user)?" Password4
- ask q_activity_database_name "What is the name of the Activity database?" String pe-activity
- ask q_activity_database_user "What is the name of the Activity database user?" String pe-activity
- ask q_activity_database_password "What is the password for ${q_activity_database_user?} (the database user)?" Password4
- ask q_classifier_database_name "What is the name of the Classifier database?" String pe-classifier
- ask q_classifier_database_user "What is the name of the Classifier database user?" String pe-classifier
- ask q_classifier_database_password "What is the password for ${q_classifier_database_user?} (the database user)?" Password4
- fi
- fi
- if ! is_upgrade && [ ! y = "${q_puppetdb_install?}" ]; then
- display_newline
- echo "In order to properly classify ${q_puppetdb_hostname?} as a PuppetDB server and provide continued management, you must provide the PuppetDB database information." | display_wrapped_text
- display_newline
- ask q_puppetdb_database_name "What is the name of the PuppetDB database?" String pe-puppetdb
- ask q_puppetdb_database_user "What is the name of the PuppetDB database user?" String pe-puppetdb
- ask q_puppetdb_database_password "What is the password for ${q_puppetdb_database_user?} (the database user)?" Password4
- fi
- # If it's a remote postgres and we're not just saving answers, we
- # need to validate that we can connect, and that the
- # databases/users exist. If it's our postgres, we're already going
- # to be ensuring those things, so no need to validate.
- if [ n = "${q_database_install?}" ] && ! is_save_answers; then
- if [ -n "${t_path_to_psql}" ]; then
- verify_db
- need_to_verify_db=n
- else
- need_to_verify_db=y
- fi
- fi
- fi
- else
- display_newline
- if [ "${PLATFORM_NAME}" = "aix" ] ; then
- PLATFORM_DISPLAY_NAME=AIX
- else
- PLATFORM_DISPLAY_NAME=${PLATFORM_NAME}
- fi
- echo "${PLATFORM_DISPLAY_NAME?} ${PLATFORM_RELEASE?} only supports agent installation."
- q_puppetmaster_install='n'
- q_puppet_enterpriseconsole_install='n'
- q_puppetca_install='n'
- q_puppetagent_install='y'
- q_puppet_cloud_install='n'
- q_puppetdb_install='n'
- q_database_install='n'
- q_all_in_one_install='n'
- ask q_puppetagent_server "Puppet master hostname to connect to?" String puppet
- if ( ! is_save_answers ) && [ 'n' = "${q_skip_master_verification:-"n"}" ] ; then
- while ! tcp_port_in_use "${q_puppetagent_server}" 8140 ; do
- query_about_master_connectivity
- done
- fi
- : ${q_fail_on_unsuccessful_master_lookup:='y'}
- : ${q_puppetca_hostname:=${q_puppetagent_server?}}
- fi
- if [ y = "${q_puppetagent_install?}" ]; then
- t_default_agent_certname="${PLATFORM_HOSTNAME?}"
- # If we're on a master, and the user isn't driving the installer from an answer file
- # set the certname to the master certname provided earlier
- if [ y = "${q_puppetmaster_install?}" ]; then
- # Update the default value to remove visually jarring difference in default/answer.
- t_default_agent_certname="${q_puppetmaster_certname}"
- if [ -z "${q_puppetagent_certname}" ]; then
- q_puppetagent_certname="${q_puppetmaster_certname}"
- fi
- : ${q_puppetagent_server:="${q_puppetmaster_certname?}"}
- else
- ask q_puppetagent_certname "Puppet agent needs a unique name (\"certname\") for its certificate; this can be an arbitrary string. Certname for this node?" StringForceLowerCase "${t_default_agent_certname}"
- if [ y = "${q_puppet_enterpriseconsole_install?}" -a n = "${q_puppetmaster_install?}" ]; then
- : ${q_puppet_enterpriseconsole_master_hostname:="${q_puppetagent_server?}"}
- fi
- fi
- : ${q_puppetmaster_enterpriseconsole_certname:="${q_puppetagent_certname?}"}
- fi
- if [ y = "${q_puppetdb_install?}" ]; then
- # We need to know this for classification, and to bind host and port
- : ${q_puppetdb_hostname:="${q_puppetagent_certname?}"}
- fi
- if [ ! y = "${q_puppetmaster_install?}" ] && [ y = "${q_puppet_enterpriseconsole_install?}" -o y = "${q_puppetdb_install?}" ]; then
- # In case the user deleted their old answer file we do this on upgrades as well
- ask q_puppetmaster_certname "What is the certname of the puppet master?" StringForceLowerCase "${q_puppetagent_server?}"
- fi
- if [ 'xaix' = "x${PLATFORM_NAME}" -a -x /usr/sbin/updtvpkg ] ; then
- display_product 'updtvpkg' "Puppet Enterprise contains rpm packages that depend on native AIX libraries. In order to resolve these dependencies correctly, the 'updtvpkg' command is used to populate the rpm database with the native AIX libraries already present on the system."
- ask q_run_updtvpkg "Run 'updtvpkg' to populate the rpm database with available native libaries? (this may take some time)" Yn
- else
- q_run_updtvpkg=n
- fi
- #...[ Vendor packages ].................................................
- enqueue_vendor_packages
- # Determine which vendor packages are missing
- t_main_missing_vendor_packages="$(missing_queued_packages)"
- # Continue interview
- if [ ! -z "${ANSWER_FILE_TO_SAVE?}" ]; then
- # When saving answers, always prompt user to install vendor packages
- display_product 'Vendor Packages' "Puppet Enterprise may require additional packages from your operating system vendor. You will need to either install these yourself, or allow them to be automatically installed from your operating system's package repositories."
- if [ ! -z "${t_main_missing_vendor_packages?}" ]; then
- if [ -d `platform_package_dir` ]; then
- display_missing_vendor_packages "${t_main_missing_vendor_packages?}"
- fi
- fi
- ask q_vendor_packages_install 'Allow automatic installation of these packages?' Yn
- elif [ ! -z "${t_main_missing_vendor_packages?}" ]; then
- # Check for RHEL4 here and bail if we're missing vendor packages.
- # RHEL4 doesn't have yum, so installing vendor packages is an exercise left to the user
- if [ "${VENDOR_PACKAGE_OFFLINE?}" = "true" ]; then
- display_product 'Vendor Packages' "The installer has detected that Puppet Enterprise requires additional packages from your operating system vendor's repositories, and cannot automatically install them. The installer will now exit so you can install them manually."
- display_missing_vendor_packages "${t_main_missing_vendor_packages?}"
- display_failure "You must manually install the above packages before installing Puppet Enterprise."
- else
- # When running, only prompt user to install vendor packages if needed
- display_product 'Vendor Packages' "The installer has detected that Puppet Enterprise requires additional packages from your operating system vendor's repositories, and can automatically install them. If you choose not to install these packages automatically, the installer will exit so you can install them manually."
- display_missing_vendor_packages "${t_main_missing_vendor_packages?}"
- ask q_vendor_packages_install 'Install these packages automatically?' Yn
- if [ ! y = "${q_vendor_packages_install?}" ]; then
- display_failure "You must manually install the above packages before installing Puppet Enterprise."
- fi
- fi
- else
- # Set default value
- q_vendor_packages_install="${q_vendor_packages_install:-"n"}"
- fi
- #...[ Check for existing configuration ]...............................
- if is_pe_service_install && ! is_upgrade && [ "y" != "${q_skip_backup}" ]; then
- if ( ! is_save_answers ) && [ -x /etc/puppetlabs ] ; then
- display_newline
- display " === Existing Puppet Enterprise configuration detected === "
- display_newline
- display_comment "It looks like Puppet Enterprise had been installed on this machine and it was uninstalled without the purge option (-p). The existing configuration cannot be reused by this installer. You can either quit this installation or the installer can move your existing configuration to /etc/puppetlabs.<yyyymmddHHMMSS>.bak and create a new one."
- ask q_backup_and_purge_old_configuration "Would you like to backup your existing configuration and continue installing Puppet Enterprise?" yN
- if [ "y" != "${q_backup_and_purge_old_configuration?}" ]; then
- quit 1
- fi
- else
- q_backup_and_purge_old_configuration='n'
- fi
- fi
- #...[ Check directory environment migration ]..............................
- if is_upgrade; then
- if ! run "/opt/puppet/bin/rake -s -f '${INSTALLER_DIR}/environments.rake' environments:check 2>/dev/null"; then
- display_newline
- display_comment "It looks like Puppet Enterprise has discovered issues with your current configuration and will be unable to migrate to directory environments if these issues are not fixed first. Please make the appropriate changes to puppet.conf or contact Puppet Labs support. Puppet Enterprise components and configuration files have not been changed."
- ask q_environment_check_failed "Are you sure you want to continue?" yN
- if [ "y" != "${q_environment_check_failed?}" ]; then
- quit 1
- fi
- fi
- fi
- #---[ Quit early ]------------------------------------------------------
- if ! is_pe_service_install && [ ! y = "${q_puppetagent_install?}" -a ! y = "${q_puppet_cloud_install?}" ]; then
- display_newline
- display_major_separator
- display_newline
- display_failure "Nothing selected for installation"
- fi
- #---[ Confirm ]---------------------------------------------------------
- display_step 'CONFIRM PLAN'
- render_plan
- #---[ Set OFFER_ROLL_BACK flag ]----------------------------------------------
- # Up until this point, we have made no changes to a system, so a failure
- # prior to this point would not require any sort of roll-back to restore
- # a system to a pristine state. After this point, we may have modified a
- # a system, if only to save an answers file, so we can offer to roll
- # back using the uninstaller
- OFFER_ROLL_BACK='y'
- if is_upgrade; then
- if is_pe_service_install; then
- display "It is strongly recommended that you take a snapshot of this system before performing the upgrade."
- display_newline
- fi
- ask q_install 'Perform upgrade?' Yn
- else
- ask q_install 'Perform installation?' Yn
- fi
- if [ y = "${q_database_install}" ]; then
- #---[ Sanitize q_database_host for ssl ]-----------------------------
- if [ "${q_database_host}" == 'localhost' ]; then
- q_database_host=$q_puppetagent_certname
- fi
- fi
- if [ ! y = "${q_install?}" ]; then
- display_newline
- display_major_separator
- display_newline
- display "!! Installation cancelled"
- display_newline
- display_major_separator
- do_save_answers
- quit 1
- else
- if ! is_upgrade; then
- if [ "y" = "${q_backup_and_purge_old_configuration:-'n'}" ]; then
- run "mv /etc/puppetlabs /etc/puppetlabs.$(date '+%Y%m%d%H%M%S').bak"
- run "./puppet-enterprise-uninstaller -py"
- fi
- if [ "y" = "${q_backup_and_purge_old_database_directory:-'n'}" ]; then
- run "mv /opt/puppet/var/lib/pgsql /opt/puppet/var/lib/pgsql.$(date '+%Y%m%d%H%M%S').bak"
- fi
- fi
- do_save_answers
- if [ y = "${q_database_install}" ]; then
- save_database_info_etc
- fi
- fi
- #---[ Ignore q_upgrade_installation=y, #16091 ]------------------------
- ignore_duplicate 'upgrade'
- #---[ Export answers for use with erb ]---------------------------------
- for t_env_variable in `set | ${PLATFORM_EGREP?} '^q_' | sed -n 's/^\(q_[^=][^=]*\).*$/\1/p'`; do export ${t_env_variable}; done
- # Export a non-q variable
- export PLATFORM_HOSTNAME
- # PLATFORM_HOSTNAME_SHORT is used by databases.erb
- export PLATFORM_HOSTNAME_SHORT
- # This is needed for puppet.conf
- export PLATFORM_NAME
- export PLATFORM_PUPPET_GROUP
- export PLATFORM_PUPPET_USER
- # These are used to make package repos
- export PE_VERSION
- export PLATFORM_TAG
- #---[ Stop services for upgrade ]---------------------------------------
- if is_upgrade ; then
- display_comment "Stopping Puppet Enterprise services for upgrade"
- if is_puppetmaster; then
- if [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ]; then
- puppet_resource "service pe-httpd ensure=stopped"
- else
- puppet_resource "service pe-puppetserver ensure=stopped"
- fi
- fi
- if is_console; then
- puppet_resource "service pe-httpd ensure=stopped"
- puppet_resource "service pe-puppet-dashboard-workers ensure=stopped"
- fi
- if is_puppetdb; then
- puppet_resource "service pe-puppetdb ensure=stopped"
- fi
- if is_postgres; then
- puppet_resource "service pe-postgresql ensure=stopped"
- fi
- for agent in pe-puppet pe-puppet-agent puppetagent; do
- puppet_resource "service $agent ensure=stopped" ||:
- done
- fi
- #---[ Enqueue our packages ]--------------------------------------------
- # NONPORTABLE
- # Install cloud gems
- if [ y = ${q_puppet_cloud_install?} ]; then
- handle_cloud
- fi
- if [ "${VENDOR_PACKAGE_OFFLINE?}" = "true" ]; then
- # If we've gotten this far, all of the vendor packages are installed,
- # so we need to unset the variable to allow the installation of all
- # rpms regardless of presence.
- unset PACKAGES_REQUIRED
- fi
- enqueue_agent_packages
- if [ y = "${q_puppetmaster_install?}" ]; then
- if is_upgrade && [ 'y' != "${q_all_in_one_install?}" -a "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- # Upgrade these packages so we don't have to worry about
- # metapackages from earlier releases like 3.0.1
- # Also upgrade these before the master manifest is applied so
- # the version-check in the puppetserver package doesn't conflict
- enqueue_package 'pe-httpd'
- enqueue_package 'pe-passenger'
- enqueue_package 'pe-rubygem-rack'
- fi
- enqueue_package 'pe-java'
- enqueue_package 'pe-puppetserver'
- enqueue_package 'pe-puppetserver-common'
- enqueue_package 'pe-license'
- enqueue_package 'pe-puppet-license-cli'
- enqueue_package 'pe-puppetdb-terminus'
- enqueue_package 'pe-console-services-termini'
- fi
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- case "${PLATFORM_NAME?}" in
- amazon | centos | rhel | sles)
- ;;
- ubuntu | debian)
- enqueue_package 'pe-httpd-mpm-worker'
- ;;
- *)
- display_failure "Do not know how to install HTTPD on this platform"
- ;;
- esac
- enqueue_package 'pe-httpd'
- enqueue_package 'pe-passenger'
- enqueue_package 'pe-rubygem-rack'
- enqueue_package 'pe-mcollective-client'
- # PostgreSQL Packages for PE Console
- enqueue_package 'pe-postgresql'
- # Dashboard Packages
- enqueue_package 'pe-puppet-dashboard'
- enqueue_package 'pe-bundler'
- # Live Management Packages
- enqueue_package 'pe-libevent'
- enqueue_package 'pe-memcached'
- enqueue_package 'pe-live-management'
- # Console packages
- enqueue_package 'pe-console-auth'
- enqueue_package 'pe-console'
- enqueue_package 'pe-certificate-manager'
- enqueue_package 'pe-license'
- enqueue_package 'pe-license-status'
- enqueue_package 'pe-event-inspector'
- enqueue_package 'pe-console-services'
- #FIXME Replace this with with explicit use of pe-psql
- t_path_to_psql='/opt/puppet/bin/psql'
- fi
- # This entire if block can be removed once we are managing postgresql with
- # the new puppet_enterprise module
- if [ y = "${q_puppetdb_install?}" ]; then
- # we are installing /opt/puppet/bin/psql at this point
- # override any previously found version
- t_path_to_psql='/opt/puppet/bin/psql'
- if [ y = "${q_database_install?}" ]; then
- enqueue_package 'pe-postgresql-server'
- enqueue_package 'pe-postgresql-contrib'
- fi
- enqueue_package 'pe-postgresql'
- enqueue_package 'pe-java'
- enqueue_package 'pe-puppetdb'
- fi
- #---[ Write out PE version ]-------------------------------------------
- # We need to do this before the puppet agent gets started for the first time
- # to ensure the version gets picked up correctly, so we pick the last time
- # before the packages are installed.
- if ! is_noop; then
- run_suppress_stdout "mkdir -p /opt/puppet && chown ${PLATFORM_ROOT_USER}:${PLATFORM_ROOT_GROUP} /opt/puppet && chmod 755 /opt/puppet"
- run_suppress_stdout "cp ${INSTALLER_DIR}/VERSION /opt/puppet/pe_build && chown ${PLATFORM_ROOT_USER}:${PLATFORM_ROOT_GROUP} /opt/puppet/pe_build && chmod 644 /opt/puppet/pe_build"
- fi
- #---[ Install support/uninstaller scripts ]------------------------------------------------
- if is_pe_service_install; then
- run_suppress_stdout "mkdir -p /opt/puppet/bin && chown ${PLATFORM_ROOT_USER}:${PLATFORM_ROOT_GROUP} /opt/puppet/bin && chmod 755 /opt/puppet/bin"
- run_suppress_stdout "mkdir -p /opt/puppet/share/installer && chown ${PLATFORM_ROOT_USER}:${PLATFORM_ROOT_GROUP} /opt/puppet/share /opt/puppet/share/installer && chmod 755 /opt/puppet/share /opt/puppet/share/installer"
- run_suppress_stdout "cp ${INSTALLER_DIR}/puppet-enterprise-support ${INSTALLER_DIR}/puppet-enterprise-uninstaller /opt/puppet/bin"
- run_suppress_stdout "cp ${INSTALLER_DIR}/utilities /opt/puppet/share/installer/utilities"
- run_suppress_stdout "chown ${PLATFORM_ROOT_USER}:${PLATFORM_ROOT_GROUP} /opt/puppet/bin/puppet-enterprise-support /opt/puppet/bin/puppet-enterprise-uninstaller /opt/puppet/share/installer/utilities"
- run_suppress_stdout "chmod 755 /opt/puppet/bin/puppet-enterprise-support /opt/puppet/bin/puppet-enterprise-uninstaller /opt/puppet/share/installer/utilities"
- fi
- #---[ Install packages ]------------------------------------------------
- display_step 'INSTALL PACKAGES'
- if [ 'y' = "${q_run_updtvpkg}" ] ; then
- display_comment 'Running /usr/sbin/updtvpkg to update rpm database...'
- run_suppress_output '/usr/sbin/updtvpkg'
- fi
- if is_upgrade && is_console && [ y = "${q_database_transfer?}" ]; then
- display_comment "Analyzing current database settings..."
- t_transfer_console_tmp_dir=$(run "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:tmpdir RAILS_ENV=production" | tail -n 1)
- #we need to know the original database names, user names, hosts and ports, and we need to store passwords to the source databases in a secure way
- t_source_console_db_name=$(run "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:console:current_database RAILS_ENV=production" | tail -n 1)
- display_comment "Current console database name is ${t_source_console_db_name?}"
- t_source_console_user_name=$(run "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:console:current_user RAILS_ENV=production" | tail -n 1)
- display_comment "Current console database user is ${t_source_console_user_name?}"
- t_source_console_host=$(run "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:console:current_host RAILS_ENV=production" | tail -n 1)
- display_comment "Current console database host is ${t_source_console_host?}"
- t_source_console_port=$(run "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:console:current_port RAILS_ENV=production" | tail -n 1)
- display_comment "Current console database port is ${t_source_console_port?}"
- # let's store the passwords now
- run "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:console:store_source_password RAILS_ENV=production TMPDIR=${t_transfer_console_tmp_dir?}"
- # we need the target databases to be migrated down to the same version as the source databases
- # therefore we need to figure out what the versions of current databases are
- t_source_console_db_version=$(run "/opt/puppet/bin/rake -s -R '${INSTALLER_DIR}' -f /opt/puppet/share/puppet-dashboard/Rakefile db:version RAILS_ENV=production" | ${PLATFORM_EGREP?} '^Current version:' | sed 's/^Current version: //g')
- display_comment "Current console database migration version is ${t_source_console_db_version?}"
- fi
- if is_upgrade; then
- display_comment 'Upgrading packages'
- fi
- install_queued_packages
- # On early versions of 3.7 for SLES 10 we installed pe-agent and rubygem-net-ssh, but they are no longer
- # needed, so we remove them here, if installed, to clean up.
- if [[ $PLATFORM_TAG =~ ${SLES_10_REGEX?} ]]; then
- if is_upgrade; then
- if is_package_installed 'pe-agent'; then
- run_suppress_output "rpm -e --allmatches pe-agent"
- fi
- if is_package_installed 'pe-rubygem-net-ssh'; then
- run_suppress_output "rpm -e --allmatches pe-rubygem-net-ssh"
- fi
- fi
- fi
- # If we couldn't verify postgres earlier (because it wasn't installed),
- # verify it now.
- if [ y = "${need_to_verify_db:-'n'}" ]; then
- verify_db
- fi
- #---[ Generate "puppet.conf" ]------------------------------------------
- if is_upgrade; then
- if [ y = "${q_puppetmaster_install?}" ] && [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ]; then
- run "/opt/puppet/bin/rake -s -f '${INSTALLER_DIR}/environments.rake' environments:upgrade"
- fi
- else
- run "/opt/puppet/bin/erb -T - '${INSTALLER_DIR}/erb/puppet.conf.erb' > '/etc/puppetlabs/puppet/puppet.conf'"
- # Create the production environment.
- run "mkdir -p /etc/puppetlabs/puppet/environments/production/manifests /etc/puppetlabs/puppet/environments/production/modules"
- fi
- #---[ Setup packages ]--------------------------------------------------
- # All of these roles need local copies of the modules
- if is_pe_service_install; then
- install_puppet_modules
- # We just installed a bunch of modules, or upgraded them, which means
- # we may have swapped out a bunch of parser functions that had
- # already be loaded by pe-puppet (I'm looking at you, pe_accounts and
- # create_resource). Removing the contents of the libdir will get rid
- # of all the crufty functions, and pluginsync will later repopulate it
- # with new versions of the modules.
- if is_upgrade; then
- run_suppress_stdout "rm -rf `/opt/puppet/bin/puppet agent --configprint libdir`"
- fi
- fi
- if [ y = "${q_puppetmaster_install?}" ]; then
- if [ n = "${q_all_in_one_install}" ]; then
- # Uses
- # q_puppetmaster_enterpriseconsole_hostname
- # q_puppetdb_hostname
- run "/opt/puppet/bin/erb -T - '${INSTALLER_DIR?}/erb/autosign.conf.erb' >> '/etc/puppetlabs/puppet/autosign.conf'"
- fi
- # Generate the master's SSL server certificate
- if ! is_noop && [ ! -e "$(/opt/puppet/bin/puppet master --configprint hostcert)" ]; then
- run_suppress_stdout "/opt/puppet/bin/puppet cert --generate ${q_puppetmaster_certname?} --ca_name 'Puppet CA generated on ${q_puppetca_hostname?} at $(date '+%Y-%m-%d %H:%M:%S %z')' --dns_alt_names '${q_puppetmaster_dnsaltnames?}' --verbose --color=false || true"
- fi
- # Mcollective utilizes a shared public/private key between all users
- # as well as a private/public key pair for each mco client.
- # Every MCO server than needs a copy of that MCO clients public key.
- # There currently exists no ideal solution to this problem short of writing a new
- # mco security provider. For now we are forced to generate the public/private keypairs on
- # the master during initial install, and then send them as files in the catalog to whichever nodes get
- # classified with the correct mcollective classes.
- t_mco_shared_keypair_name="pe-internal-mcollective-servers"
- t_mco_peadmin_key_name="pe-internal-peadmin-mcollective-client"
- t_mco_console_key_name="pe-internal-puppet-console-mcollective-client"
- for certname in ${t_mco_shared_keypair_name?} ${t_mco_peadmin_key_name?} ${t_mco_console_key_name?}; do
- generate_certs $certname
- done
- display "Generating mcollective password..."
- gen_password "/etc/puppetlabs/mcollective/credentials"
- run_suppress_stdout "chown ${PLATFORM_PUPPET_USER}:${PLATFORM_PUPPET_GROUP} /etc/puppetlabs/mcollective/credentials"
- run_suppress_stdout "chmod 600 /etc/puppetlabs/mcollective/credentials"
- fi
- if [ ! -s "/etc/puppetlabs/puppet/ssl/private_keys/${q_puppetagent_certname?}.pem" ]; then
- if [ "${q_puppetmaster_install?}" = y ]; then
- run_suppress_stdout "/opt/puppet/bin/puppet cert generate ${q_puppetagent_certname?} --color=false" || :
- else
- # Generate the agent credentials by attempting to contact the master
- run_suppress_stdout "/opt/puppet/bin/puppet certificate find ${q_puppetagent_certname?} --ca-location remote --ca_server ${q_puppetca_hostname?}" || :
- fi
- fi
- # Generate the certs for the console
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- # On upgrades pe-internal-dashboard certs may
- # have been moved from puppet's ssl dir, so here we copy them back to
- # have a consistent way to check if they need to be generated
- t_dashboard_cert_dir="/opt/puppet/share/puppet-dashboard/certs/"
- t_dashboard_client_private_key="${t_dashboard_cert_dir?}/pe-internal-dashboard.private_key.pem"
- t_dashboard_client_public_key="${t_dashboard_cert_dir?}/pe-internal-dashboard.public_key.pem"
- t_dashboard_client_cert="${t_dashboard_cert_dir?}/pe-internal-dashboard.cert.pem"
- t_puppet_ssl_dir="/etc/puppetlabs/puppet/ssl"
- if [ -s "${t_dashboard_client_private_key?}" -a ! -s "${t_puppet_ssl_dir?}/private_keys/pe-internal-dashboard.pem" ]; then
- run_suppress_stdout "cp ${t_dashboard_client_private_key?} ${t_puppet_ssl_dir?}/private_keys/pe-internal-dashboard.pem"
- run_suppress_stdout "cp ${t_dashboard_client_public_key?} ${t_puppet_ssl_dir?}/public_keys/pe-internal-dashboard.pem"
- run_suppress_stdout "cp ${t_dashboard_client_cert?} ${t_puppet_ssl_dir?}/certs/pe-internal-dashboard.pem"
- fi
- for certname in "pe-internal-dashboard" "pe-internal-classifier"; do
- generate_certs $certname
- done
- fi
- if [ y = "${q_puppetmaster_install?}" ]; then
- display_comment 'Setting up puppet master...'
- if ! is_upgrade; then
- t_environmentpath=$(/opt/puppet/bin/puppet config print environmentpath)
- run "/opt/puppet/bin/erb -T - '${INSTALLER_DIR}/erb/site.pp.erb' > '${t_environmentpath}/production/manifests/site.pp'"
- fi
- create_package_repo
- #Setup a repo for the simplified agent and future masters / amq nodes to use
- setup_package_repo
- # Copy modules into place to be served via puppet's fileserver to
- # secondary masters
- create_module_mount
- if is_upgrade && [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- display_comment 'Updating puppet.conf SSL settings'
- puppet_resource "pe_ini_setting /etc/puppetlabs/puppet/puppet.conf path=/etc/puppetlabs/puppet/puppet.conf section=master setting=ssl_client_header ensure=absent"
- puppet_resource "pe_ini_setting /etc/puppetlabs/puppet/puppet.conf path=/etc/puppetlabs/puppet/puppet.conf section=master setting=ssl_client_verify_header ensure=absent"
- # TODO: These files should be backed up
- display_comment 'Cleaning up old httpd configuration'
- t_httpd_confdir="/etc/puppetlabs/httpd/conf.d"
- run_suppress_stdout "rm -f ${t_httpd_confdir}/puppetmaster.conf"
- run_suppress_stdout "rm -f ${t_httpd_confdir}/headers.conf"
- run_suppress_stdout "rm -rf /var/opt/lib/pe-puppetmaster"
- if [ 'y' != "${q_all_in_one_install?}" ] ; then
- run_suppress_stdout "rm -f ${t_httpd_confdir}/passenger-extra.conf"
- else
- bounce_service "pe-httpd"
- fi
- fi
- # Uses
- # q_puppetmaster_certname
- # q_puppetmaster_dnsaltnames
- # q_puppetmaster_enterpriseconsole_hostname
- # q_puppetmaster_enterpriseconsole_certname
- # q_puppet_enterpriseconsole_install
- # q_puppetdb_hostname
- # t_puppetserver_java_args
- apply_template_manifest "master.pp.erb"
- remove_package_repo
- if is_upgrade; then
- # These files are not used by PE anymore, they can be safely removed
- for file in send_cert_request.rb receive_signed_cert.rb; do
- if [ -f "/opt/puppet/bin/${file}" ]; then
- run_suppress_stdout "rm -f /opt/puppet/bin/${file}"
- fi
- done
- display_comment 'Updating puppet.conf report processors'
- puppet_resource "pe_ini_subsetting /etc/puppetlabs/puppet/puppet.conf path=/etc/puppetlabs/puppet/puppet.conf section=master setting=reports subsetting=https subsetting_separator=, ensure=absent"
- puppet_resource "pe_ini_subsetting /etc/puppetlabs/puppet/puppet.conf path=/etc/puppetlabs/puppet/puppet.conf section=master setting=reports subsetting=http subsetting_separator=, ensure=absent"
- puppet_resource "pe_ini_setting /etc/puppetlabs/puppet/puppet.conf path=/etc/puppetlabs/puppet/puppet.conf section=master setting=reporturl ensure=absent"
- # Remove the MRI master-specific packages if this is a master-only
- # install from PE < 3.7. We don't remove them on an all-in-one
- # because they're still used by the console.
- if [ 'y' != "${q_all_in_one_install?}" -a "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- puppet_package "pe-httpd" "purged"
- case "${PLATFORM_NAME?}" in
- amazon | centos | rhel | sles)
- puppet_package "pe-httpd-devel" "purged"
- puppet_package "pe-mod_ssl" "purged"
- puppet_package "pe-libapr" "purged"
- puppet_package "pe-libaprutil" "purged"
- puppet_package "pe-libldap" "purged"
- ;;
- ubuntu | debian)
- puppet_package "pe-httpd-utils" "purged"
- puppet_package "pe-httpd-common" "purged"
- puppet_package "pe-httpd-bin" "purged"
- ;;
- esac
- puppet_package "pe-passenger" "purged"
- puppet_package "pe-rubygem-rack" "purged"
- fi
- fi
- t_wait_for_puppetmaster_url="https://${q_puppetmaster_certname?}:8140"
- if ! is_noop && ! wait_for_service $t_wait_for_puppetmaster_url 120 ; then
- display_failure "The puppet master service failed to start within 120 seconds; unable to proceed"
- fi
- fi
- display_comment 'Checking the agent certificate name detection...'
- if run_suppress_stdout "/opt/puppet/bin/puppet agent --configprint certname --color=false"; then
- if [ ! y = "${q_puppetmaster_install?}" ] && [ y = "${q_puppet_enterpriseconsole_install?}" -o y = "${q_puppetdb_install?}" -o y = "${q_puppet_agent_first_run:-"y"}" ] ; then
- display_comment 'Setting up puppet agent...'
- run_suppress_stdout "/opt/puppet/bin/puppet agent --test --color=false || true"
- fi
- else
- display_failure 'The agent certificate name was incorrect; please check that your system can correctly resolve its own FQDN in DNS.'
- fi
- if [ y = "${q_database_install?}" ]; then
- display_comment 'Setting up the database...'
- # Verify that we can set the password here.
- configure_postgresql_server
- # Now we've created databases and users, so if we roll back, we should run it with the -d flag
- ROLL_BACK_DBS='y'
- fi
- # If this is a fresh db install we should be setting the password to the desired password. If we are just setting the db up we
- # have already verified the credentials so we should be able to just set up the dbs.
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- display_comment 'Setting up the console...'
- # If q_public_hostname is set by the answer file, use that. Otherwise,
- # it defaults to the detected hostname, unless we're on EC2 in which
- # case we use the public-hostname from the EC2 data.
- if [ -z "${q_public_hostname}" ]; then
- q_public_hostname="${PLATFORM_HOSTNAME?}"
- export q_public_hostname
- fi
- if ! is_upgrade; then
- # Generate the session key for settings.yml
- t_session_key_dashboard=`dd if=/dev/urandom bs=4k count=512 2> /dev/null | sha512sum | $PLATFORM_AWK '{print $1}'`
- export t_session_key_dashboard
- fi
- if is_upgrade; then
- #...[ settings.yml ]....................................................
- if [ -s '/etc/puppetlabs/puppet-dashboard/settings.yml' ]; then
- backup_file '/etc/puppetlabs/puppet-dashboard/settings.yml'
- # Add new settings if they don't exist
- if [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- add_key_and_value_to_yaml_file '/etc/puppetlabs/puppet-dashboard/settings.yml' 'dashboard_server' ${q_puppetagent_certname?}
- add_key_and_value_to_yaml_file '/etc/puppetlabs/puppet-dashboard/settings.yml' 'dashboard_port' '4435'
- add_key_and_value_to_yaml_file '/etc/puppetlabs/puppet-dashboard/settings.yml' 'nc_api_url' "'https://${q_puppetagent_certname?}:4433/classifier-api'"
- add_key_and_value_to_yaml_file '/etc/puppetlabs/puppet-dashboard/settings.yml' 'certificate_whitelist' '/etc/puppetlabs/puppet-dashboard/dashboard-certificate-whitelist'
- fi
- # Live Management Toggle settings
- # If the LM variable doesn't exist in settings.yml, add it
- # Otherwise, if the user has specified a desired state, change it to that
- if ! ${PLATFORM_EGREP?} -q 'disable_live_management:' '/etc/puppetlabs/puppet-dashboard/settings.yml'; then
- run "sed -i -e '\$i\\\n# Set this to true to disable Live Management on this node\n# If this is changed, you must restart pe-httpd' '/etc/puppetlabs/puppet-dashboard/settings.yml'"
- if [ y = "${q_disable_live_management}" ]; then
- run "sed -i -e '\$i\\disable_live_management: true' '/etc/puppetlabs/puppet-dashboard/settings.yml'"
- else
- run "sed -i -e '\$i\\disable_live_management: false' '/etc/puppetlabs/puppet-dashboard/settings.yml'"
- fi
- else
- if [ y = "${q_disable_live_management}" ]; then
- run "sed -i -e 's/disable_live_management:.*/disable_live_management: true/' '/etc/puppetlabs/puppet-dashboard/settings.yml'"
- elif [ n = "${q_disable_live_management}" ]; then
- run "sed -i -e 's/disable_live_management:.*/disable_live_management: false/' '/etc/puppetlabs/puppet-dashboard/settings.yml'"
- fi
- fi
- fi
- if [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- # Export old classification data to a file to be imported later. Only for PE < 3.7 upgrades
- if ! verbose_bundle_exec "/opt/puppet/bin/rake -s -f /opt/puppet/share/puppet-dashboard/Rakefile configuration:export['/opt/puppet/share/installer/pe_classification_export.yml'] RAILS_ENV=production"; then
- display_failure "Rake task could not export classification."
- fi
- fi
- fi
- if is_upgrade; then
- export t_stomp_password=$(get_ini_field '/etc/puppetlabs/mcollective/server.cfg' 'plugin.activemq.pool.1.password')
- fi
- # Uses
- # @certname = ENV['q_puppetagent_certname']
- # @database_host = ENV['q_database_host']
- # @database_port = ENV['q_database_port']
- # @database = ENV['q_enterpriseconsole_database_name']
- # @user = ENV['q_enterpriseconsole_database_user']
- # @password = ENV['q_enterpriseconsole_database_password'].gsub("'","")
- # @master = ENV['q_puppetagent_server']
- # @master_certname = ENV['q_puppetmaster_certname']
- # @ca = ENV['q_puppetca_hostname']
- # @puppetdb = ENV['q_puppetdb_hostname']
- # @puppetdb_port = ENV['q_puppetdb_port']
- # @classifier_database_name = ENV['q_classifier_database_name']
- # @classifier_database_user = ENV['q_classifier_database_user']
- # @classifier_database_password = ENV['q_classifier_database_password'].gsub("'","")
- # @rbac_database_name = ENV['q_rbac_database_name']
- # @rbac_database_user = ENV['q_rbac_database_user']
- # @rbac_database_password = ENV['q_rbac_database_password'].gsub("'","")
- # @activity_database_name = ENV['q_activity_database_name']
- # @activity_database_user = ENV['q_activity_database_user']
- # @activity_database_password = ENV['q_activity_database_password'].gsub("'","")
- # @secret_token = ENV['t_session_key_dashboard']
- # @manage_config = ENV['IS_UPGRADE'] != 'y'
- # @migrate_db = true
- # @disable_live_management = ENV['q_disable_live_management'] == 'y'
- # @stomp_password = ENV['t_stomp_password']
- # t_console_services_java_args
- apply_template_manifest "console.pp.erb"
- fi
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- display_comment "Starting http server for puppet console."
- # NONPORTABLE
- case "${PLATFORM_NAME?}" in
- ubuntu | debian)
- # Ubuntu's "pe-httpd" can't cope with ".bak" files.
- run_suppress_stdout "rm -rf /etc/puppetlabs/httpd/*/*.bak"
- # Ubuntu's "pe-httpd" doesn't enable some important modules by default
- run_suppress_stdout "/opt/puppet/sbin/a2enmod ssl headers authnz_ldap ldap"
- # Need to munge the /etc/default/pe-puppet-dashboard-workers init file for sanity
- [ -f '/etc/default/pe-puppet-dashboard-workers' ] && run_suppress_stdout "sed -i 's/### START=no/START=yes/g' /etc/default/pe-puppet-dashboard-workers"
- ;;
- esac
- bounce_service 'pe-memcached'
- enable_service 'pe-memcached'
- # Start the http service if we're an enterprise console with our certs automatically signed.
- bounce_service 'pe-httpd'
- enable_service 'pe-httpd'
- run_suppress_stdout 'touch /var/log/pe-puppet-dashboard/certificate_manager.log'
- run_suppress_stdout 'chown -Rvf puppet-dashboard:puppet-dashboard /var/log/pe-puppet-dashboard/*'
- bounce_service 'pe-puppet-dashboard-workers'
- enable_service 'pe-puppet-dashboard-workers'
- fi
- # On the PuppetDB node, this will configure PuppetDB itself.
- if [ y = "${q_puppetdb_install?}" ]; then
- configure_puppetdb
- fi
- if [ y = "${q_puppet_enterpriseconsole_install?}" ]; then
- # Postgres could be restarted again after configuring PuppetDB, so we
- # wait for it to come back up before proceeding to run rake tasks which
- # modify the DB. If we're not noop.
- if ! is_noop && [ y = "${q_database_install?}" ] && ! wait_for_db 20; then
- display_failure "The PostgreSQL server failed to start; unable to proceed"
- fi
- if ! is_noop; then
- # We are assuming that the node classifier will be on the same node as
- # the console for 3.7
- t_wait_for_nc_url="https://${q_puppetagent_certname}:4433/classifier-api"
- display 'Waiting for Node Classifier to start...'
- if wait_for_nc $t_wait_for_nc_url 120; then
- display 'Applying configurations...'
- if is_upgrade && [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- # Import old classification data from a file to new classifier. Only for PE < 3.7 upgrades
- if ! verbose_bundle_exec "/opt/puppet/bin/rake -s -f /opt/puppet/share/puppet-dashboard/Rakefile configuration:import['/opt/puppet/share/installer/pe_classification_export.yml'] RAILS_ENV=production"; then
- display "!!! WARNING: Could not import classification; please check the logs in '/var/log/pe-console-services/' for more information."
- t_import_classification_failure='y'
- fi
- fi
- if ! is_upgrade || [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- # Make update-classes call to ensure node classifier
- # has all of the classes from the puppet master before
- # classifying PE.
- export t_platform_puppet_class=$(platform_puppet_class) # set class from utilities for classification
- if run "/opt/puppet/bin/ruby ${INSTALLER_DIR}/pe-classification.rb"; then
- display 'All configurations were successfully applied!'
- else
- display "!!! WARNING: The node classifier was unable to apply configurations; please check the logs in '/var/log/pe-console-services/' for more information."
- t_classification_failure='y'
- fi
- fi
- else
- display "!!! WARNING: The node classifier could not be reached; please check the logs in '/var/log/pe-console-services/' for more information."
- t_classification_failure='y'
- fi
- # Set the superuser password in RBAC to be the password supplied for dashboard auth.
- # This script depends on console-services being up and running. The wait_for_nc
- # function above is one way to ensure that RBAC will be available, so this script
- # should be after the if block above.
- if ! is_upgrade || [ "$(echo_vercmp 3.7.0 $CURRENT_PE_VERSION)" = "1" ] ; then
- if run "/opt/puppet/bin/ruby ${INSTALLER_DIR}/update-superuser-password.rb"; then
- echo 'Updated superuser password'
- else
- t_update_superuser_pass_failure='y'
- fi
- fi
- fi
- fi
- if ! is_noop && [ y = "${q_all_in_one_install?}" ]; then
- t_wait_for_puppetdb_url="https://${q_puppetdb_hostname?}:${q_puppetdb_port?}"
- if wait_for_service $t_wait_for_puppetdb_url 120; then
- run_suppress_stdout "/opt/puppet/bin/puppet agent --test --color=false || true"
- fi
- fi
- #---[ Finish installation ]---------------------------------------------
- cron_enable
- run "/opt/puppet/bin/facter --puppet --yaml > /etc/puppetlabs/mcollective/facts.yaml"
- run "chown ${PLATFORM_PUPPET_USER}:${PLATFORM_PUPPET_GROUP} /etc/puppetlabs/puppet/puppet.conf"
- run "chmod 600 /etc/puppetlabs/puppet/puppet.conf"
- # Until we've finished upgrading all the PE nodes, agent runs will fail to
- # retrieve a fresh catalog. We need to delete the cached catalog in order
- # to avoid it reverting anything we've changed.
- run_suppress_stdout "rm -f /var/opt/lib/pe-puppet/client_data/catalog/${q_puppetagent_certname?}.json"
- # If this is a master or console or puppetdb install, ignore the q_puppet_agent_first_run value
- if is_pe_service_install || [ y = "${q_puppet_agent_first_run:-"y"}" ] ; then
- # NONPORTABLE
- case "${PLATFORM_NAME?}" in
- amazon | centos | rhel | sles | aix | eos)
- bounce_service 'pe-puppet'
- enable_service 'pe-puppet'
- ;;
- ubuntu | debian | cumulus)
- run "printf \"START=true\nDAEMON_OPTS=''\n\" > /etc/default/pe-puppet"
- bounce_service 'pe-puppet'
- enable_service 'pe-puppet'
- ;;
- solaris)
- if [ "${PLATFORM_RELEASE?}" = "10" ] ; then
- if [ ! -d /etc/puppetlabs ]; then
- run_suppress_stdout "mkdir /etc/puppetlabs"
- run_suppress_stdout "chown ${PLATFORM_ROOT_USER}:${PLATFORM_ROOT_GROUP} /etc/puppetlabs"
- run_suppress_stdout "chmod 755 /etc/puppetlabs"
- fi
- run_suppress_stdout "/usr/sbin/svccfg import /var/svc/manifest/network/pe-puppet.xml"
- run_suppress_stdout "/usr/sbin/svcadm enable svc:/network/pe-puppet:default"
- else
- # We deliver the manifest and puppet.conf as part of the
- # pe-puppet package on Solaris 11, so no need to create their
- # directories. Service manifest import happens as part of
- # package installation, so we only need to enable it.
- run_suppress_stdout "/usr/sbin/svcadm enable svc:/network/pe-puppet:default"
- fi
- ;;
- *)
- display_failure "Do not know how to start puppet agent service on this platform"
- ;;
- esac
- fi
- if [ y = "${q_puppet_enterpriseconsole_install}" ]; then
- if run_suppress_stdout "getent hosts ${q_public_hostname?}"; then
- t_is_hostname_resolvable='y'
- else
- t_is_hostname_resolvable='n'
- fi
- fi
- display_step 'DONE'
- if is_upgrade; then
- display 'Thanks for upgrading Puppet Enterprise!'
- else
- display 'Thanks for installing Puppet Enterprise!'
- fi
- display_newline
- if [ ! y = "${q_all_in_one_install}" ] ; then
- if is_upgrade ; then
- t_upgrade_or_install="upgrade"
- else
- t_upgrade_or_install="installation"
- fi
- if [ y = "${q_puppetdb_install?}" ] ; then
- echo "You have completed the ${t_upgrade_or_install?} of PuppetDB. You should now complete your ${t_upgrade_or_install?} by installing or upgrading the Puppet Enterprise Console. See the documentation for more assistance: http://docs.puppetlabs.com/pe/latest" | display_wrapped_text
- display_newline
- display_newline
- elif [ y = "${q_puppetmaster_install?}" ] ; then
- if is_upgrade; then
- echo "You have completed the upgrade of the puppet master, you should now proceed to upgrade PuppetDB. See the documentation for further assistance: http://docs.puppetlabs.com/pe/latest The PuppetDB node MUST be upgraded prior to installing the Console." | display_wrapped_text
- else
- echo "You have completed the installation of the puppet master, you should now proceed to install PuppetDB on a unique node. See the documentation for further assistance: http://docs.puppetlabs.com/pe/latest The PuppetDB node MUST be installed prior to installing the Console." | display_wrapped_text
- fi
- display_newline
- display_newline
- fi
- fi
- echo "To learn more and get started using Puppet Enterprise, refer to the Puppet Enterprise Quick Start Guide (http://docs.puppetlabs.com/pe/latest/quick_start.html) and the Puppet Enterprise Deployment Guide (http://docs.puppetlabs.com/guides/deployment_guide/index.html)." | display_wrapped_text
- display_newline
- display_newline
- # on an enterprise console install
- if [ y = "${q_puppet_enterpriseconsole_install}" ]; then
- # check to see if the hostname is resolvable
- if [ n = "${t_is_hostname_resolvable?}" ]; then
- # give an error message if not
- display_newline
- echo "We could not resolve the host at ${q_public_hostname?}. If this hostname is actually correct, no further action is needed and you can disregard further error messages." | display_wrapped_text
- display_newline
- else
- # and display the console URL otherwise
- CONSOLE_URL="https://${q_public_hostname?}:${q_puppet_enterpriseconsole_httpd_port?}"
- if [ '443' = "${q_puppet_enterpriseconsole_httpd_port?}" ]; then
- CONSOLE_URL="https://${q_public_hostname?}"
- fi
- display " The console can be reached at the following URI:"
- display " * ${CONSOLE_URL?}"
- display_newline
- fi
- fi
- display_major_separator
- display_newline
- display_comment 'NOTES'
- display_newline
- if ! is_upgrade; then
- echo 'Puppet Enterprise has been installed to "/opt/puppet," and its configuration files are located in "/etc/puppetlabs".' | display_wrapped_text
- display_newline
- display_newline
- fi
- if [ ! -z "${ANSWER_FILE_TO_SAVE?}" ]; then
- echo "Answers from this session saved to '${ANSWER_FILE_TO_SAVE?}'" | display_wrapped_text
- display_newline
- if [ "y" = "${q_database_install}" ] ; then
- if is_upgrade ; then
- t_database_info_answers="/etc/puppetlabs/installer/database_info.${PE_VERSION?}.upgrade"
- else
- t_database_info_answers="/etc/puppetlabs/installer/database_info.install"
- fi
- echo "In addition, auto-generated database users and passwords have been saved to '${t_database_info_answers?}'" | display_wrapped_text
- display_newline
- echo "!!! WARNING: Do not discard these files! All auto-generated database users and passwords have been saved in them. You will need this information to configure the console role during installation." | display_wrapped_text
- display_newline
- fi
- display_newline
- else
- echo "!!! WARNING: An answer file could not be saved so, to prevent data loss, supplied and auto-generated database users' passwords have been saved to '/etc/puppetlabs/installer/database_info.install'. This file should be secured as soon as possible!" | display_wrapped_text
- display_newline
- display_newline
- fi
- # XXX Don't warn about ports for now. Too lazy to do anything about the console port.
- if ! is_upgrade; then
- warn_open_ports
- display_newline
- fi
- # If the wait_for_nc function fails to get a class update, the installer won't be able to
- # classify PE. Make sure the user knows this.
- if [ "${t_classification_failure}" == 'y' ]; then
- # make this better
- echo "!!! WARNING: Installer failed to classify Puppet Enterprise. Puppet Enterprise will not be able to manage itself because of this. Check '/var/log/pe-console-services/' for more information." | display_wrapped_text
- display_newline
- fi
- if [ "${t_update_superuser_pass_failure}" == 'y' ]; then
- # make this better
- echo "!!! WARNING: Installer failed to update superuser password. This leaves your PE installation at risk. Check '/var/log/pe-console-services/' for more information. Log into the console (user: admin, password: admin) as soon as possible and change the admin users password through the console." | display_wrapped_text
- display_newline
- puppet_resource "service pe-console-services ensure=stopped"
- fi
- if [ "${t_import_classification_failure}" == 'y' ];then
- echo "!!! WARNING: Installer failed to upgrade classification. Check '/var/log/pe-console-services/' for more information." | display_wrapped_text
- display_newline
- echo "Stopping pe-console-services to avoid puppet runs from failing or behaving incorrectly." | display_wrapped_text
- display_newline
- puppet_resource "service pe-console-services ensure=stopped"
- fi
- display_minor_separator
- display_newline
- # Clean up the stuff we exported
- unset q_public_hostname
- # Get rid of the development.log
- if [ -f "/var/log/pe-puppet-dashboard/development.log" ]; then
- run "rm -f /var/log/pe-puppet-dashboard/development.log"
- fi
- quit
- fi
- #===[ End ]=============================================================
- # vim: tabstop=4:softtabstop=4:shiftwidth=4:expandtab
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement